import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
import { dirname } from "path";
import { PendingBlinkInvoiceRecord } from "../providers/blink/types";
import { IBlinkInvoiceStore } from "./StoreContracts";

interface BlinkInvoiceStoreFile {
  invoices: PendingBlinkInvoiceRecord[];
}

export class BlinkInvoiceStoreService implements IBlinkInvoiceStore {
  constructor(private readonly filePath: string) {
    this.ensureStore();
  }

  async savePending(record: PendingBlinkInvoiceRecord): Promise<void> {
    const store = this.read();
    const existingIndex = store.invoices.findIndex(
      (invoice) =>
        invoice.reference === record.reference || invoice.payment_hash.toLowerCase() === record.payment_hash.toLowerCase()
    );

    if (existingIndex >= 0) {
      store.invoices[existingIndex] = record;
    } else {
      store.invoices.push(record);
    }

    this.write(store);
  }

  async findPendingByPaymentHashOrReference(
    paymentHash?: string,
    reference?: string
  ): Promise<PendingBlinkInvoiceRecord | null> {
    const normalizedPaymentHash = String(paymentHash || "").trim().toLowerCase();
    const normalizedReference = String(reference || "").trim();

    const invoice = this.read().invoices.find((record) => {
      return (
        (normalizedPaymentHash && record.payment_hash.toLowerCase() === normalizedPaymentHash) ||
        (normalizedReference && record.reference === normalizedReference) ||
        (normalizedReference && record.provider_reference === normalizedReference)
      );
    });

    return invoice || null;
  }

  async markConfirmed(
    reference: string,
    providerReference: string | undefined,
    transactionStatus: string,
    walletCurrency: string,
    rawWebhookPayload: Record<string, unknown>
  ): Promise<void> {
    const store = this.read();
    const index = store.invoices.findIndex((invoice) => invoice.reference === reference);
    if (index === -1) {
      return;
    }

    store.invoices[index] = {
      ...store.invoices[index],
      status: "confirmed",
      provider_reference: providerReference || null,
      transaction_status: transactionStatus,
      wallet_currency: walletCurrency,
      raw_webhook_payload: rawWebhookPayload,
      updated_at: new Date().toISOString(),
    };

    this.write(store);
  }

  private ensureStore(): void {
    if (!existsSync(dirname(this.filePath))) {
      mkdirSync(dirname(this.filePath), { recursive: true });
    }

    if (!existsSync(this.filePath)) {
      this.write({ invoices: [] });
    }
  }

  private read(): BlinkInvoiceStoreFile {
    const parsed = JSON.parse(readFileSync(this.filePath, "utf8")) as BlinkInvoiceStoreFile;
    return {
      invoices: Array.isArray(parsed.invoices) ? parsed.invoices : [],
    };
  }

  private write(payload: BlinkInvoiceStoreFile): void {
    writeFileSync(this.filePath, JSON.stringify(payload, null, 2), "utf8");
  }
}
