import { DepositEvent } from "../../types";
import { WebhookRequestError } from "../../services/AlchemyWebhookPayloadValidator";
import { IBlinkInvoiceStore } from "../../services/StoreContracts";
import { BlinkWebhookPayload, PendingBlinkInvoiceRecord } from "./types";

interface BlinkWebhookProcessResult {
  events: DepositEvent[];
  metrics: {
    ignored: number;
    unsupported: number;
    unmatched: number;
  };
}

export class BlinkWebhookProcessor {
  constructor(private readonly blinkInvoiceStore: IBlinkInvoiceStore) {}

  async process(body: unknown): Promise<BlinkWebhookProcessResult> {
    const payload = this.validatePayload(body);
    const eventType = String(payload.eventType || "").trim();

    if (eventType !== "receive.lightning") {
      return {
        events: [],
        metrics: {
          ignored: 1,
          unsupported: 0,
          unmatched: 0,
        },
      };
    }

    const transaction = payload.transaction;
    const paymentHash = String(transaction?.initiationVia?.paymentHash || "").trim().toLowerCase();
    if (!paymentHash) {
      throw new WebhookRequestError("Blink receive.lightning webhook missing paymentHash", 400);
    }

    const providerReference = String(transaction?.id || "").trim();
    const transactionStatus = String(transaction?.status || "").trim().toLowerCase();
    if (transactionStatus !== "success") {
      return {
        events: [],
        metrics: {
          ignored: 1,
          unsupported: 0,
          unmatched: 0,
        },
      };
    }

    const pendingRecord = await this.blinkInvoiceStore.findPendingByPaymentHashOrReference(
      paymentHash,
      providerReference || undefined
    );

    if (!pendingRecord) {
      console.warn("blink webhook received for unknown invoice", {
        payment_hash: paymentHash,
        provider_reference: providerReference || null,
      });
      return {
        events: [],
        metrics: {
          ignored: 0,
          unsupported: 0,
          unmatched: 1,
        },
      };
    }

    const amountSats = this.resolveAmount(transaction?.settlementAmount, pendingRecord.amount_sats);
    const settlementCurrency = String(transaction?.settlementCurrency || pendingRecord.currency || "")
      .trim()
      .toUpperCase();
    const walletCurrency = String(
      transaction?.settlementDisplayPrice?.walletCurrency || settlementCurrency || pendingRecord.currency || ""
    )
      .trim()
      .toUpperCase();

    if (settlementCurrency !== "BTC" || walletCurrency !== "BTC") {
      return {
        events: [],
        metrics: {
          ignored: 0,
          unsupported: 1,
          unmatched: 0,
        },
      };
    }

    const occurredAt = this.resolveOccurredAt(transaction?.createdAt);
    const rawPayload = payload as Record<string, unknown>;
    await this.blinkInvoiceStore.markConfirmed(
      pendingRecord.reference,
      providerReference,
      transactionStatus,
      walletCurrency,
      rawPayload
    );

    const normalizedPayload = {
      provider: "blink" as const,
      network: "bitcoin_lightning" as const,
      asset: "BTC" as const,
      user_id: pendingRecord.user_id,
      amount_sats: amountSats,
      payment_hash: paymentHash,
      provider_reference: providerReference,
      status: "confirmed" as const,
      raw_payload: {
        webhook: rawPayload,
        pending_invoice: {
          reference: pendingRecord.reference,
          payment_hash: pendingRecord.payment_hash,
          payment_request: pendingRecord.payment_request,
        },
      },
    };

    return {
      events: [
        {
          source: "blink",
          status: "confirmed",
          idempotency_key: `blink:${paymentHash}`,
          user_id: pendingRecord.user_id,
          wallet_address: pendingRecord.reference,
          amount: String(amountSats),
          amount_sats: amountSats,
          asset: "BTC",
          tx_hash: paymentHash,
          payment_hash: paymentHash,
          provider_reference: providerReference || null,
          chain_type: "bitcoin_lightning",
          network: "bitcoin_lightning",
          transaction_status: transactionStatus,
          wallet_currency: walletCurrency,
          block_number: null,
          occurred_at: occurredAt,
          raw_payload: normalizedPayload.raw_payload,
        },
      ],
      metrics: {
        ignored: 0,
        unsupported: 0,
        unmatched: 0,
      },
    };
  }

  private validatePayload(body: unknown): BlinkWebhookPayload {
    if (!body || typeof body !== "object") {
      throw new WebhookRequestError("Missing Blink webhook payload", 400);
    }

    return body as BlinkWebhookPayload;
  }

  private resolveAmount(value: unknown, fallback: number): number {
    if (typeof value === "number" && Number.isFinite(value)) {
      return Math.trunc(value);
    }

    if (typeof value === "string" && value.trim()) {
      const parsed = Number(value);
      if (Number.isFinite(parsed)) {
        return Math.trunc(parsed);
      }
    }

    return fallback;
  }

  private resolveOccurredAt(value?: string): string {
    if (value && !Number.isNaN(Date.parse(value))) {
      return new Date(value).toISOString();
    }

    return new Date().toISOString();
  }
}
