import * as anchor from "@coral-xyz/anchor";
import { Transaction } from "@solana/web3.js";
import { expect } from "chai";
import fetch from "node-fetch";
import { getTestContext } from "../setup";

describe("Start Auction (API)", () => {
  it("Local Admin Germany Starts Published Auction", async () => {
    const ctx = getTestContext();
    const {
      connection,
      program,
      axumBaseUrl,
      localAdminGermany,
      localAdminGermanyPda,
      auctionPda,
      auctionId,
    } = ctx;

    console.log("Starting auction...");
    console.log(`  Auction PDA: ${auctionPda.toBase58()}`);
    console.log(`  Auction ID: ${auctionId}`);
    console.log(`  Local Admin: ${localAdminGermanyPda.toBase58()}`);

    // ============================================================
    // STEP 1: Verify Auction State Before (should be Published)
    // ============================================================
    console.log("Verifying auction state before start...");

    const auctionBefore = await program.account.auction.fetch(auctionPda);
    expect(auctionBefore.status).to.deep.equal({ published: {} });
    console.log("✓ Auction status: Published");

    // Wait for start_time to be reached (auction was published with start_time = current + 5 seconds)
    const startTime = auctionBefore.startTime.toNumber();
    const currentTime = Math.floor(Date.now() / 1000);

    if (currentTime < startTime) {
      const waitTime = (startTime - currentTime + 10) * 1000; // +10 second buffer
      console.log(`Waiting ${waitTime}ms for auction start time...`);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }

    // ============================================================
    // STEP 2: Create API Request Payload
    // ============================================================
    const request = {
      auction_pda: auctionPda.toBase58(),
      local_admin_pubkey: localAdminGermany.publicKey.toBase58(),
    };

    console.log("Calling API to create start auction transaction...");

    // ============================================================
    // STEP 3: Call Axum API to Get Unsigned Transaction
    // ============================================================
    const createTxResponse = await fetch(
      `${axumBaseUrl}/api/primary-market/start-auction`,
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(request),
      }
    );

    if (!createTxResponse.ok) {
      const error = await createTxResponse.text();
      throw new Error(`Failed to create transaction: ${error}`);
    }

    const { transaction_base64, message } = await createTxResponse.json();
    console.log(`API Response: ${message}`);

    // ============================================================
    // STEP 4: Deserialize and Sign Transaction
    // ============================================================
    const txBuffer = Buffer.from(transaction_base64, "base64");
    const transaction = Transaction.from(txBuffer);

    console.log("Transaction signer (expected):");
    console.log("  Local Admin Germany:", localAdminGermany.publicKey.toBase58());

    // Sign with localAdminGermany (the only required signer)
    transaction.sign(localAdminGermany);

    console.log("Transaction signed locally");

    // ============================================================
    // STEP 5: Submit Signed Transaction to Backend
    // ============================================================
    const signedTxBase64 = transaction.serialize().toString("base64");
    const submitTxResponse = await fetch(`${axumBaseUrl}/api/submit-tx`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ transaction_base64: signedTxBase64 }),
    });

    if (!submitTxResponse.ok) {
      const error = await submitTxResponse.text();
      throw new Error(`Failed to submit transaction: ${error}`);
    }

    const { signature } = await submitTxResponse.json();
    console.log(`✓ Transaction signature: ${signature}`);

    // ============================================================
    // STEP 6: Verify On-Chain State - AUCTION STARTED
    // ============================================================
    console.log("Verifying auction state after start...");

    const auctionAfter = await program.account.auction.fetch(auctionPda);

    expect(auctionAfter.status).to.deep.equal({ active: {} });
    expect(auctionAfter.localAdmin.equals(localAdminGermanyPda)).to.be.true;
    expect(auctionAfter.auctionId.toNumber()).to.equal(auctionId);
    expect(auctionAfter.euaVolumeOffered.toNumber()).to.equal(1000);
    expect(auctionAfter.totalBids).to.equal(0);

    console.log("✓ Auction account state verified");
    console.log(`  - Auction ID: ${auctionAfter.auctionId.toNumber()}`);
    console.log(`  - Status: Active`);
    console.log(`  - EUA Volume Offered: ${auctionAfter.euaVolumeOffered.toNumber()}`);
    console.log(`  - Total Bids: ${auctionAfter.totalBids}`);

    // ============================================================
    // STEP 7: Verify Local Admin State (unchanged)
    // ============================================================
    const localAdmin = await program.account.localAdmin.fetch(localAdminGermanyPda);

    expect(localAdmin.activeAuction).to.not.be.null;
    expect(localAdmin.activeAuction.equals(auctionPda)).to.be.true;

    console.log(`✓ Local Admin state verified:`);
    console.log(`  - Active Auction: ${localAdmin.activeAuction.toBase58()}`);
    console.log(`  - Total Auctions: ${localAdmin.totalAuctions.toNumber()}`);

    // ============================================================
    // STEP 8: Verify Events/Logs
    // ============================================================
    const txDetails = await connection.getTransaction(signature, {
      commitment: "confirmed",
      maxSupportedTransactionVersion: 0,
    });

    if (txDetails?.meta?.logMessages) {
      const logs = txDetails.meta.logMessages;

      const hasStartLog = logs.some((log) =>
        log.includes("Auction started") || log.includes("AuctionStarted")
      );

      if (hasStartLog) {
        console.log("✓ Auction started event found in logs");
      }
    }

    console.log("✓ Auction started successfully via API");
    console.log("\n=== Summary ===");
    console.log(`Auction PDA: ${auctionPda.toBase58()}`);
    console.log(`Auction ID: ${auctionId}`);
    console.log(`Status: Published → Active`);
    console.log(`EUA Volume: ${auctionAfter.euaVolumeOffered.toNumber()}`);
    console.log(`Total Bids: ${auctionAfter.totalBids}`);
  });

  // Optional: Test error cases
  // it("Should Reject Starting Auction Before Start Time", async () => {
  //   // This would require publishing a new auction with a far future start time
  //   // and trying to start it immediately
  // });

  // it("Should Reject Starting Auction That Is Not Published", async () => {
  //   // This would require having an auction in a different status
  // });

  // it("Should Reject Starting Auction with Wrong Local Admin", async () => {
  //   // Try to start with localAdminFrance instead of localAdminGermany
  // });
});
