import os
import requests
import sqlite3
import json
from hashlib import sha256
from ellipticcurve import Ecdsa, Signature
from ellipticcurve.privateKey import PrivateKey
from ellipticcurve.publicKey import PublicKey
import struct
import binascii

# Configuration
CHAINSTACK_API_KEY = os.environ.get("CHAINSTACK_API_KEY")  # Get API key from environment variables
NETWORK = "bitcoin"  # Bitcoin network (mainnet, testnet, regtest)
DATABASE_FILE = "btc_transaction_data.db"
BLOCK_SCAN_CHUNK_SIZE = 100  # Number of blocks to scan in each API call

def create_database():
    """Creates the SQLite database and table if they don't exist."""
    conn = sqlite3.connect(DATABASE_FILE)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS transactions (
            txid TEXT PRIMARY KEY,
            block_height INTEGER,
            r TEXT,
            s TEXT,
            z TEXT,
            input_index INTEGER
        )
    """)
    conn.commit()
    conn.close()


def get_latest_block_height():
    """Gets the latest block height from Chainstack."""
    url = f"https://btc.mainnet.chainstacklabs.com/latest-block" #using mainnet as default
    headers = {"x-api-key": CHAINSTACK_API_KEY}

    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
        data = response.json()
        return data["result"]["height"]
    except requests.exceptions.RequestException as e:
        print(f"Error fetching latest block height: {e}")
        return None


def get_block_transactions(block_height):
    """Gets transaction data for a specific block from Chainstack."""
    url = f"https://btc.mainnet.chainstacklabs.com/block/{block_height}/transactions"
    headers = {"x-api-key": CHAINSTACK_API_KEY}

    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        data = response.json()
        return data["result"]
    except requests.exceptions.RequestException as e:
        print(f"Error fetching transactions for block {block_height}: {e}")
        return None

def decode_varint(stream):
    """Decodes a Bitcoin varint (variable integer)."""
    first_byte = stream[0]
    if first_byte < 0xFD:
        return first_byte, 1
    elif first_byte == 0xFD:
        return struct.unpack("<H", stream[1:3])[0], 3
    elif first_byte == 0xFE:
        return struct.unpack("<I", stream[1:5])[0], 5
    elif first_byte == 0xFF:
        return struct.unpack("<Q", stream[1:9])[0], 9
    else:
        raise ValueError("Invalid varint")

def serialize_transaction(transaction, input_index, sighash_type=0x01):
    """
    Serializes a transaction for signing, following Bitcoin's rules.
    This is a simplified implementation for SIGHASH_ALL.  A full implementation
    needs to handle different SIGHASH types and input/output combinations.
    """
    # Version
    version = struct.pack("<i", transaction["version"])

    # Input Count
    input_count = struct.pack("<B", len(transaction["vin"])) #VarInt would be more correct
    # Inputs
    inputs = b""
    for i, vin in enumerate(transaction["vin"]):
        txid = binascii.unhexlify(vin["txid"])[::-1] #Reverse endianness
        vout = struct.pack("<I", vin["vout"])
        script_sig = binascii.unhexlify(vin["scriptSig"]["hex"]) if "scriptSig" in vin and "hex" in vin["scriptSig"] else b""

        #Use empty script for other inputs except the one being signed
        if i != input_index:
            script_sig = b""

        script_length = struct.pack("<B", len(script_sig)) #VarInt would be more correct
        sequence = struct.pack("<I", vin["sequence"])
        inputs += txid + vout + script_length + script_sig + sequence

    # Output Count
    output_count = struct.pack("<B", len(transaction["vout"]))  #VarInt would be more correct

    # Outputs
    outputs = b""
    for vout in transaction["vout"]:
        value = struct.pack("<q", int(vout["value"] * 100000000))  # satoshis
        script_pub_key = binascii.unhexlify(vout["scriptPubKey"]["hex"])
        script_length = struct.pack("<B", len(script_pub_key)) #VarInt would be more correct
        outputs += value + script_length + script_pub_key

    # Locktime
    locktime = struct.pack("<I", transaction["locktime"])

    # SIGHASH Type
    sighash = struct.pack("<I", sighash_type)  # SIGHASH_ALL

    return version + input_count + inputs + output_count + outputs + locktime + sighash


def extract_rsz_values(transaction, block_height):
    """
    Extracts R, S, and Z values from a transaction's inputs, calculates Z correctly.

    Args:
        transaction (dict): A dictionary representing a Bitcoin transaction.
        block_height (int): The height of the block containing the transaction.

    Returns:
        list: A list of tuples, where each tuple contains (txid, block_height, r, s, z, input_index).
    """
    txid = transaction["txid"]
    extracted_data = []

    for input_index, input_data in enumerate(transaction["vin"]):
        if "scriptSig" in input_data and "asm" in input_data["scriptSig"]:
            script_asm = input_data["scriptSig"]["asm"].split()

            try:
                # Extract signature (DER encoded)
                signature_der = bytes.fromhex(script_asm[0])
                signature = Signature.from_der(signature_der)
                r = str(signature.r)
                s = str(signature.s)


                # Calculate Z (Transaction Hash)
                serialized_tx = serialize_transaction(transaction, input_index) #Passing in transaction dict
                z_hash = sha256(serialized_tx).hexdigest() #Hash serialized Transaction
                z = str(int(z_hash, 16)) # Convert hex to integer string


                extracted_data.append((txid, block_height, r, s, z, input_index))

            except Exception as e:
                print(f"Error extracting r, s, z from scriptSig for txid {txid}, input {input_index}: {e}")
                continue

    return extracted_data

def store_data_in_database(data):
    """Stores the extracted R, S, and Z values into the SQLite database."""
    conn = sqlite3.connect(DATABASE_FILE)
    cursor = conn.cursor()
    try:
        cursor.executemany("""
            INSERT OR IGNORE INTO transactions (txid, block_height, r, s, z, input_index)
            VALUES (?, ?, ?, ?, ?, ?)
        """, data)
        conn.commit()
        print(f"Stored {len(data)} new transaction signatures in the database.")
    except sqlite3.Error as e:
        print(f"Error storing data in the database: {e}")
    finally:
        conn.close()



def main():
    """Main function to orchestrate the scanning and extraction process."""

    if not CHAINSTACK_API_KEY:
        print("Error: CHAINSTACK_API_KEY environment variable not set.")
        return

    create_database()  # Initialize the database

    latest_block_height = get_latest_block_height()
    if latest_block_height is None:
        print("Failed to get latest block height. Exiting.")
        return

    #Start scanning from a specific block height (can be adjusted)
    start_block_height = 784000
    print(f"Starting scan from block {start_block_height} to block {latest_block_height}")


    for block_height in range(start_block_height, latest_block_height + 1): # Iterate through blocks
        transactions = get_block_transactions(block_height)
        if transactions:
            all_extracted_data = []
            for transaction in transactions:
                extracted_data = extract_rsz_values(transaction, block_height)
                all_extracted_data.extend(extracted_data)  # Accumulate data from all transactions

            if all_extracted_data:
                store_data_in_database(all_extracted_data)
        else:
            print(f"No transactions found or error fetching transactions for block {block_height}")



if __name__ == "__main__":
    #Example Usage:  Run the script and pass the transaction hex as a command-line argument
    # For example: python your_script_name.py "0200000000010103212a294e0d03450f374c044a5733a2ea1dae99ad9e73076952d3cab9d78f300000000000ffffffff5540548900000000001976a914751e76e8199196d454941c45d1b3a323f1433bd688ac80b86723000000001976a91420d45a6a762535700ce9e0b216e31994335db8a588acc00cf123000000001976a914739437bb3dd6d1983e66629c5f08c70e5276937188ac00617a24000000001976a914e0b8a2baee1b77fc703455f39d51477451fc8cfc88ac40b50325000000001976a91461eb8a50c86b0584bb727dd65bed8d2400d6d5aa88acc05d1626000000001976a914f6f5431d25bbf7b12e8add9af5e3475c44a0a5b888ac00b29f26000000001976a914bf7413e8df4e7a34ce9dc13e2f2648783ec54adb88ac40062927000000001976a914105b7f253f0ebd7843adaebbd805c944bfb863e488ac805ab227000000001976a9149f0adb20baeacc38b3f49f3df6906a0e48f2df3d88ac0003c528000000001976a91486f9fea5cdecf033161dd2f8f8560768ae0a6d1488ac40574e29000000001976a914783c138ac81f6a52398564bb17455576e8525b2988ac80abd729000000001976a91435003c3ef8759c92092f8488fca59a042859018c88acc0ff602a000000001976a91467671d5490c272e3ab7ddd34030d587738df33da88ac40a8732b000000001976a914351e605fac813965951ba433b7c2956bf8ad95ce88ac80fcfc2b000000001976a91420d28d4e87543947c7e4913bcdceaa16e2f8f06188acc050862c000000001976a91424cef184714bbd030833904f5265c9c3e12a95a288ac00a50f2d000000001976a9147c99ce73e19f9fbfcce4825ae88261e2b0b0b04088ac804d222e000000001976a914c60111ed3d63b49665747b0e31eb382da519353588acc0a1ab2e000000001976a914fbc708d671c03e26661b9c08f77598a529858b5e88ac00f6342f000000001976a91438a968fdfb457654c51bcfc4f9174d6ee487bb4188ac404abe2f000000001976a9145c3862203d1e44ab3af441503e22db97b1c5097e88acc0f2d030000000001976a9149978f61b92d16c5f1a463a0995df70da1f7a7d2a88ac00475a31000000001976a9146534b31208fe6e100d29f9c9c75aac8bf06fbb3888ac409be331000000001976a914463013cd41279f2fd0c31d0a16db3972bfffac8d88ac80ef6c32000000001976a914c6927a00970d0165327d0a6db7950f05720c295c88ac00987f33000000001976a9142da63cbd251d23c7b633cb287c09e6cf888b3fe488ac40ec0834000000001976a914578d94dc6f40fff35f91f6fba9b71c46b361dff288ac80409234000000001976a9147eefddd979a1d6bb6f29757a1f463579770ba56688acc0941b35000000001976a914c01bf430a97cbcdaedddba87ef4ea21c456cebdb88ac403d2e36000000001976a9147c1a77205c03b9909663b2034faa0b544e6bc96b88ac8091b736000000001976a914f72b812932f6d7102233971d65cec0a22b89e13688acc0e54037000000001976a914695fd6dcf33f47166b25de968b2932b351b0afc488ac003aca37000000001976a91493022af9a38f3ebb0c3f15dd1c83f8fadaf64e7488ac80e2dc38000000001976a914505aaa63a5e209dfb90cee683a8e227a8c278e4788acc0366639000000001976a9142e644e46b042ffa86da35c54d7275f1abe6d491188ac008bef39000000001976a914b166c44f12c7fc565f37ff6288ee64e0f0ec9a0b88ac40df783a000000001976a914aeb0a0197442d4ade8ef41442d557b0e22b85ac088acc0878b3b000000001976a9144cfc43fe12a330c8164251e38c0c0c3c84cf86f688ac00dc143c000000001976a9144e81efec43c5195aeca0e3877664330418b8e48e88ac40309e3c000000001976a914ed673389e4b12925316f9166d56d701829e53cf888ac8084273d000000001976a91442773005f9594cd16b10985d428418acb7f352ec88ac002d3a3e000000001976a914e3f381c34a20da049779b44cae0417c7fb2898d088ac4081c33e000000001976a914c97f9591e28687be1c4d972e25be7c372a3221b488ac80d54c3f000000001976a914f4a4e1c11a5bbbd2fc139d221825407c66e0b8b488acc029d63f000000001976a914ae6804b35c82f47f8b0a42d8c5e514fe5ef0a88388ac40d2e840000000001976a914a6e4818537e42f7b3f021daa810367dad4dda16f88ac80267241000000001976a914e263b62ea294b9650615a13b926e75944c82399088acc07afb41000000001976a9147fa4515066ba6905f894b2078f9af7b1379169cf88ac00cf8442000000001976a91475f74467ce7214f1767406d5ed12012aa523c48e88ac40230e43000000001976a914f7079256aa027dc437cbb539f955472416725fc888ac80779743000000001976a914683ea8a1ef06eada90556017d44323b5c04e00f188acc0cb2044000000001976a914a58708aa98ad35c889bb36d8049bf9e9cacfd02a88ac0020aa44000000001976a914e170ef514689d7230da362a0c121a0772355051288ac40743345000000001976a914ba4c2748360a6b66263e11d1dc8658463ca5ff1888ac80c8bc45000000001976a914a24922852051a9002ebf4c864a55acb75bb4cf7588acc01c4646000000001976a91441b4b36a6c036568972380177eca2916cacd71de88ac0071cf46000000001976a914cecd3ca4319651bd3afd1e23ab66e111ed38d16d88ac40c55847000000001976a914014e15e4ea6da460cc7835e262676baa37988e4f88ac8019e247000000001976a91417a5ebfaf62e73f149e33ba674836801f13a80b988acc06d6b48000000001976a9143b6f58a75a54bfd85d1bc6c51180fdc73299232688ac00c2f448000000001976a91405257be4b57ee43fc09762d5d3a9ad4a6e1a036488ac40167e49000000001976a9143482f8986e13c018692053a784481c63a3554c9c88ac806a074a000000001976a914692a8e583866fc9056f5c61a45969fb9d868a08c88acc0be904a000000001976a914a45dae9cd5d3fde21e5aa9a95367d107267b3b8a88ac00131a4b000000001976a914ffbb35a7bb9bbe16c1aa2534f7ff11d59c8e3d1a88ac4067a34b000000001976a9147af50f73fd580f1713af3a6f9c5de49643ec6fc688ac80bb2c4c000000001976a9142fcea55e6d027a2ba7c7ebe95eedf47766730fe288acc00fb64c000000001976a91419ed3e03d19ddcedd5fa86543be820b3a795165088ac00643f4d000000001976a914ed87120066e244ff5331d5f8625873d7a3acc39c88ac40b8c84d000000001976a9145abf369388deb8072741b4eb43ef10fa9388a72988ac800c524e000000001976a914dca7ebfb78ce21884300f133d89244bc4b1b756f88acc060db4e000000001976a9145318b9d7fcc93873f768725eb68ba2c924bb07ee88ac00b5644f000000001976a914a3e3612e586fd206efb8eee6ccd58318e182829a88ac4009ee4f000000001976a9147e827e3b90da24c2a15f7b67e3bbece39955a5d088ac805d7750000000001976a914e08c4d3bc9cf2b3e2cb88de2bfaa4fe8c7aa3f2488acc0b10051000000001976a9141a4fb632f0de0c53a0a31d57f840a19e56c645ee88ac00068a51000000001976a914da56cd815fa2f0d6a4ce6d25ed7b1a01d9f9bc6b88ac405a1352000000001976a9144ccf94a1b0efd63cddeee0ef5eee5ebe720cfcbf88ac80ae9c52000000001976a914edd2e206825fa8949d1304cd82c08d64b222f2eb88acc0022653000000001976a9146b8b7830f73c5bf9e8beb9f161ad82b3bde992e488ac0057af53000000001976a9149ea3f29aaedf7da10b1488934c50a39e271b0b6488ac40ab3854000000001976a914242d790e5a168043c76f0539fd894b73ee67b3b388ac80ffc154000000001976a914628dacebb0faa7f81670e174ca4c8a95a7e3702988acc0534b55000000001976a9142ac1295b4e54b3f15bb0a99f84018d208249564588ac00a8d455000000001976a914e84818e1bf7f699aa6e28ef9edfb58209909929288ac0247304402207bf2c89fbbd336f4e45e7aa32ac4b312984f3e2ce06ea03bde3e56d660bfecda02200cc0694347f003947409aa67182cb8e52bd610c687e5f60bb29d8c22d038e600012102c584e2cb49a5aabd9ceb1e5128cecd0a7ca96628e76b1491950f021a4852d8ec00000000"
    import sys
    if len(sys.argv) > 1:
        transaction_hex = sys.argv[1]
        #Create a dummy transaction object.  Most fields will be overwritten by the deserialized transaction hex
        transaction = {
            "version": 1,
            "vin": [{"txid": "00"*32, "vout": 0, "scriptSig": {"asm": "", "hex": ""}, "sequence": 0}],
            "vout": [{"value": 0.00, "scriptPubKey": {"asm": "", "hex": ""}}],
            "locktime": 0
        }
        # Raw transaction hex decoding
        transaction_bytes = binascii.unhexlify(transaction_hex)
        stream = bytearray(transaction_bytes)

        # Parse Version
        transaction["version"] = struct.unpack("<i", stream[:4])[0]
        stream = stream[4:]

        # Parse Input Count
        input_count, offset = decode_varint(stream)