import requests
import csv
import os
from datetime import datetime

# API URLs
api_url_coinbase_usd = "https://api.exchange.coinbase.com/products/BTC-USD/book?level=2"
api_url_coinbase_usdt = "https://api.exchange.coinbase.com/products/BTC-USDT/book?level=2"
api_url_coinbase_eur = "https://api.exchange.coinbase.com/products/BTC-EUR/book?level=2"

api_url_bitfinex_usd = "https://api.bitfinex.com/v2/book/tBTCUSD/P2?len=100"
api_url_bitfinex_usdt = "https://api.bitfinex.com/v2/book/tBTCUST/P2?len=100"
api_url_bitfinex_eur = "https://api.bitfinex.com/v2/book/tBTCEUR/P2?len=100"

api_url_bitflyer_jpy = "https://api.bitflyer.com/v1/getboard?product_code=BTC_JPY"

api_url_gemini_usd = "https://api.gemini.com/v1/book/btcusd?limit_bids=0&limit_asks=0"

api_file_binance_usdt = "/var/www/html/data/orderbook.txt"

# Fetch data from APIs
response_coinbase_usd = requests.get(api_url_coinbase_usd)
response_coinbase_usdt = requests.get(api_url_coinbase_usdt)
response_coinbase_eur = requests.get(api_url_coinbase_eur)

response_bitfinex_usd = requests.get(api_url_bitfinex_usd)
response_bitfinex_usdt = requests.get(api_url_bitfinex_usdt)
response_bitfinex_eur = requests.get(api_url_bitfinex_eur)

response_bitflyer_jpy = requests.get(api_url_bitflyer_jpy)

response_gemini_usd = requests.get(api_url_gemini_usd)

data_coinbase_usd = response_coinbase_usd.json()
data_coinbase_usdt = response_coinbase_usdt.json()
data_coinbase_eur = response_coinbase_eur.json()

data_bitfinex_usd = response_bitfinex_usd.json()
data_bitfinex_usdt = response_bitfinex_usdt.json()
data_bitfinex_eur = response_bitfinex_eur.json()

data_bitflyer_jpy = response_bitflyer_jpy.json()

data_gemini_usd = response_gemini_usd.json()

# Lists to store aggregated order amounts per percentage level
coinbase_usd = []
coinbase_usdt = []
coinbase_eur = []
coinbase_bids_usd = []
coinbase_bids_usdt = []
coinbase_bids_eur = []

bitfinex_usd = []
bitfinex_usdt = []
bitfinex_eur = []
bitfinex_bids_usd = []
bitfinex_bids_usdt = []
bitfinex_bids_eur = []

bitflyer_jpy = []
bitflyer_bids_jpy = []

gemini_usd = []
gemini_bids_usd = []

binance_usdt = []
binance_bids_usdt = []

# Functions to process orderbook data for each exchange:

def get_levels_coinbase(data, percentage, currency):
    asks = data["asks"]
    orders = []
    price_limit = float(asks[0][0]) * (1 + percentage / 100)
    for ask in asks:
        if float(ask[0]) < price_limit:
            orders.append(ask)
    total_amount_ask = round(sum(float(order[1]) for order in orders))

    bids = data["bids"]
    orders = []
    price_limit_bid = float(bids[0][0]) * (1 - percentage / 100)
    for bid in bids:
        if float(bid[0]) > price_limit_bid:
            orders.append(bid)
    total_amount_bid = round(sum(float(order[1]) for order in orders))

    if currency == "USD":
        coinbase_usd.append(total_amount_ask)
        coinbase_bids_usd.append(total_amount_bid)
    elif currency == "USDT":
        coinbase_usdt.append(total_amount_ask)
        coinbase_bids_usdt.append(total_amount_bid)
    elif currency == "EUR":
        coinbase_eur.append(total_amount_ask)
        coinbase_bids_eur.append(total_amount_bid)

def get_levels_bitfinex(data, percentage, currency):
    asks = data
    orders = []
    price_limit = float(asks[0][0]) * (1 + percentage / 100)
    for ask in asks:
        if float(ask[0]) < price_limit and float(ask[2]) < 0:
            orders.append(ask)
    total_amount_ask = round(sum(abs(float(order[2])) for order in orders))  # abs because amount negative for asks

    bids = data
    orders = []
    price_limit_bid = float(bids[0][0]) * (1 - percentage / 100)
    for bid in bids:
        if float(bid[0]) > price_limit_bid and float(bid[2]) > 0:
            orders.append(bid)
    total_amount_bid = round(sum(float(order[2]) for order in orders))

    if currency == "USD":
        bitfinex_usd.append(total_amount_ask)
        bitfinex_bids_usd.append(total_amount_bid)
    elif currency == "USDT":
        bitfinex_usdt.append(total_amount_ask)
        bitfinex_bids_usdt.append(total_amount_bid)
    elif currency == "EUR":
        bitfinex_eur.append(total_amount_ask)
        bitfinex_bids_eur.append(total_amount_bid)

def get_levels_bitflyer(data, percentage):
    asks = data["asks"]
    orders = []
    price_limit = float(asks[0]["price"]) * (1 + percentage / 100)
    for ask in asks:
        if float(ask["price"]) < price_limit:
            orders.append(ask)
    total_amount_ask = round(sum(float(order["size"]) for order in orders))

    bids = data["bids"]
    orders = []
    price_limit_bid = float(bids[0]["price"]) * (1 - percentage / 100)
    for bid in bids:
        if float(bid["price"]) > price_limit_bid:
            orders.append(bid)
    total_amount_bid = round(sum(float(order["size"]) for order in orders))

    bitflyer_jpy.append(total_amount_ask)
    bitflyer_bids_jpy.append(total_amount_bid)

def get_levels_gemini(data, percentage):
    asks = data["asks"]
    orders = []
    price_limit = float(asks[0]["price"]) * (1 + percentage / 100)
    for ask in asks:
        if float(ask["price"]) < price_limit:
            orders.append(ask)
    total_amount_ask = round(sum(float(order["amount"]) for order in orders))

    bids = data["bids"]
    orders = []
    price_limit_bid = float(bids[0]["price"]) * (1 - percentage / 100)
    for bid in bids:
        if float(bid["price"]) > price_limit_bid:
            orders.append(bid)
    total_amount_bid = round(sum(float(order["amount"]) for order in orders))

    gemini_usd.append(total_amount_ask)
    gemini_bids_usd.append(total_amount_bid)

def parse_binance_file(file_path):
    bids = []
    asks = []
    with open(file_path, "r") as file:
        lines = file.readlines()
        is_bid_section = True
        for line in lines:
            if line.startswith("Asks:"):
                is_bid_section = False
                continue
            if line.startswith("Price:"):
                parts = line.strip().split(", ")
                price = float(parts[0].split(": ")[1])
                quantity = float(parts[1].split(": ")[1])
                if is_bid_section:
                    bids.append([price, quantity])
                else:
                    asks.append([price, quantity])
    return {"bids": bids, "asks": asks}

def get_levels_binance(data, percentage):
    asks = data["asks"]
    orders = []
    price_limit = float(asks[0][0]) * (1 + percentage / 100)
    for ask in asks:
        if float(ask[0]) < price_limit:
            orders.append(ask)
    total_amount_ask = round(sum(order[1] for order in orders))

    bids = data["bids"]
    orders = []
    price_limit_bid = float(asks[0][0]) * (1 - percentage / 100)
    for bid in bids:
        if float(bid[0]) > price_limit_bid:
            orders.append(bid)
    total_amount_bid = round(sum(order[1] for order in orders))

    binance_usdt.append(total_amount_ask)
    binance_bids_usdt.append(total_amount_bid)

# Parse Binance orderbook file
data_binance_usdt = parse_binance_file(api_file_binance_usdt)

# Settings
steps = 0.8
num_steps = 30

# Process each percentage level for all exchanges
for i in range(num_steps):
    pct = steps * (i + 1)
    get_levels_coinbase(data_coinbase_usd, pct, "USD")
    get_levels_coinbase(data_coinbase_usdt, pct, "USDT")
    get_levels_coinbase(data_coinbase_eur, pct, "EUR")

    get_levels_bitfinex(data_bitfinex_usd, pct, "USD")
    get_levels_bitfinex(data_bitfinex_usdt, pct, "USDT")
    get_levels_bitfinex(data_bitfinex_eur, pct, "EUR")

    get_levels_bitflyer(data_bitflyer_jpy, pct)

    get_levels_gemini(data_gemini_usd, pct)

    get_levels_binance(data_binance_usdt, pct)

# Calculate combined totals (asks and bids) for Coinbase and Bitfinex
coinbase_total_ask = [coinbase_usd[i] + coinbase_usdt[i] + coinbase_eur[i] for i in range(num_steps)]
coinbase_total_bid = [coinbase_bids_usd[i] + coinbase_bids_usdt[i] + coinbase_bids_eur[i] for i in range(num_steps)]

bitfinex_total_ask = [bitfinex_usd[i] + bitfinex_usdt[i] + bitfinex_eur[i] for i in range(num_steps)]
bitfinex_total_bid = [bitfinex_bids_usd[i] + bitfinex_bids_usdt[i] + bitfinex_bids_eur[i] for i in range(num_steps)]

lowest_ask_coinbase_usd = float(data_coinbase_usd["asks"][0][0])

price_steps_ask = [lowest_ask_coinbase_usd * (1 + steps / 100 * (i + 1)) for i in range(num_steps)]
price_steps_bid = [lowest_ask_coinbase_usd * (1 - steps / 100 * (i + 1)) for i in range(num_steps)]

timestamp = datetime.utcnow().isoformat()

# Prepare data rows for each step, now including timestamp
rows_to_append = []
for i in range(num_steps):
    row = {
        "timestamp": timestamp,
        "step_pct": steps * (i + 1),
        "price_ask": price_steps_ask[i],
        "price_bid": price_steps_bid[i],
        "coinbase_ask_usd": coinbase_usd[i],
        "coinbase_ask_usdt": coinbase_usdt[i],
        "coinbase_ask_eur": coinbase_eur[i],
        "coinbase_bid_usd": coinbase_bids_usd[i],
        "coinbase_bid_usdt": coinbase_bids_usdt[i],
        "coinbase_bid_eur": coinbase_bids_eur[i],
        "bitfinex_ask_usd": bitfinex_usd[i],
        "bitfinex_ask_usdt": bitfinex_usdt[i],
        "bitfinex_ask_eur": bitfinex_eur[i],
        "bitfinex_bid_usd": bitfinex_bids_usd[i],
        "bitfinex_bid_usdt": bitfinex_bids_usdt[i],
        "bitfinex_bid_eur": bitfinex_bids_eur[i],
        "bitflyer_ask_jpy": bitflyer_jpy[i],
        "bitflyer_bid_jpy": bitflyer_bids_jpy[i],
        "gemini_ask_usd": gemini_usd[i],
        "gemini_bid_usd": gemini_bids_usd[i],
        "binance_ask_usdt": binance_usdt[i],
        "binance_bid_usdt": binance_bids_usdt[i],
        "coinbase_total_ask": coinbase_total_ask[i],
        "coinbase_total_bid": coinbase_total_bid[i],
        "bitfinex_total_ask": bitfinex_total_ask[i],
        "bitfinex_total_bid": bitfinex_total_bid[i],
    }
    rows_to_append.append(row)

# CSV file path
csv_file = "orderbook_levels.csv"

# Define fieldnames with timestamp first
fieldnames = [
    "timestamp",
    "step_pct",
    "price_ask",
    "price_bid",
    "coinbase_ask_usd",
    "coinbase_ask_usdt",
    "coinbase_ask_eur",
    "coinbase_bid_usd",
    "coinbase_bid_usdt",
    "coinbase_bid_eur",
    "bitfinex_ask_usd",
    "bitfinex_ask_usdt",
    "bitfinex_ask_eur",
    "bitfinex_bid_usd",
    "bitfinex_bid_usdt",
    "bitfinex_bid_eur",
    "bitflyer_ask_jpy",
    "bitflyer_bid_jpy",
    "gemini_ask_usd",
    "gemini_bid_usd",
    "binance_ask_usdt",
    "binance_bid_usdt",
    "coinbase_total_ask",
    "coinbase_total_bid",
    "bitfinex_total_ask",
    "bitfinex_total_bid"
]

# Check if CSV exists
file_exists = os.path.isfile(csv_file)

# Open file in append mode
with open(csv_file, "a", newline="") as csvfile:
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    # Write header only if file is new
    if not file_exists:
        writer.writeheader()

    # Write all rows (all % steps for this timestamp)
    for row in rows_to_append:
        writer.writerow(row)