import { WebhookRequestError } from "../../services/AlchemyWebhookPayloadValidator";
import { IBlinkInvoiceStore } from "../../services/StoreContracts";
import { BlinkClient } from "./BlinkClient";
import {
  LightningInvoiceCreateRequest,
  LightningInvoiceResponse,
  PendingBlinkInvoiceRecord,
} from "./types";

interface BlinkInvoiceServiceOptions {
  btcWalletId?: string;
  defaultExpiresInMinutes?: number;
}

export class BlinkInvoiceService {
  private readonly btcWalletId?: string;
  private readonly defaultExpiresInMinutes?: number;

  constructor(
    private readonly blinkClient: Pick<BlinkClient, "createLightningInvoice" | "getBtcWalletId">,
    private readonly blinkInvoiceStore: IBlinkInvoiceStore,
    options: BlinkInvoiceServiceOptions = {}
  ) {
    this.btcWalletId = options.btcWalletId?.trim();
    this.defaultExpiresInMinutes = options.defaultExpiresInMinutes;
  }

  async createInvoice(input: LightningInvoiceCreateRequest): Promise<LightningInvoiceResponse> {
    const currency = String(input.currency || "").trim().toUpperCase();
    if (currency !== "BTC") {
      throw new WebhookRequestError("currency must be BTC for Blink Lightning invoices", 400);
    }

    if (!Number.isInteger(input.user_id) || input.user_id <= 0) {
      throw new WebhookRequestError("user_id must be a positive integer", 400);
    }

    if (!Number.isInteger(input.amount_sats) || input.amount_sats <= 0) {
      throw new WebhookRequestError("amount_sats must be a positive integer", 400);
    }

    const reference = String(input.reference || "").trim();
    if (!reference) {
      throw new WebhookRequestError("reference is required", 400);
    }

    const walletId = this.btcWalletId || (await this.blinkClient.getBtcWalletId());
    const invoice = await this.blinkClient.createLightningInvoice({
      amount: input.amount_sats,
      walletId,
      externalId: reference,
      memo: `Deposit for user ${input.user_id}`,
      expiresIn: this.defaultExpiresInMinutes,
    });

    const response: LightningInvoiceResponse = {
      provider: "blink",
      network: "bitcoin_lightning",
      asset: "BTC",
      payment_request: invoice.paymentRequest,
      payment_hash: invoice.paymentHash,
      amount_sats: invoice.satoshis,
      expires_at: this.resolveExpiresAt(invoice.createdAt, this.defaultExpiresInMinutes),
      reference,
    };

    const now = new Date().toISOString();
    const pendingRecord: PendingBlinkInvoiceRecord = {
      ...response,
      user_id: input.user_id,
      currency,
      status: "pending",
      created_at: now,
      updated_at: now,
      raw_invoice_payload: {
        invoice,
      },
      raw_webhook_payload: null,
    };

    await this.blinkInvoiceStore.savePending(pendingRecord);
    return response;
  }

  async findPendingInvoice(
    paymentHash?: string,
    reference?: string
  ): Promise<PendingBlinkInvoiceRecord | null> {
    return this.blinkInvoiceStore.findPendingByPaymentHashOrReference(paymentHash, reference);
  }

  private resolveExpiresAt(createdAt: number, expiresInMinutes?: number): string | null {
    if (!createdAt || !expiresInMinutes || expiresInMinutes <= 0) {
      return null;
    };

    return new Date((createdAt + expiresInMinutes * 60) * 1000).toISOString();
  }
}
