import { randomUUID } from "node:crypto";
import { getPool } from "../db/pool";

export type PayoutMode = "merchant_direct" | "manual";

export interface MerchantEntity {
  id: string;
  merchant_code: string;
  legal_name: string;
  brand_name?: string;
  settlement_account_reference?: string;
  settlement_account_type?: string;
  payout_mode: PayoutMode;
  fee_profile_id?: string;
  status: "active" | "inactive";
  onboarding_status: "pending" | "approved" | "rejected";
  created_at: string;
  updated_at: string;
}

function nowIso() {
  return new Date().toISOString();
}

function makeCode(id: string) {
  return `m_${id.slice(0, 6)}`;
}

function toPublic(entity: MerchantEntity) {
  return entity;
}

function mapRowToMerchant(row: any): MerchantEntity {
  return {
    id: row.id,
    merchant_code: row.merchant_code,
    legal_name: row.legal_name,
    brand_name: row.brand_name || undefined,
    settlement_account_reference: row.settlement_account_reference || undefined,
    settlement_account_type: row.settlement_account_type || undefined,
    payout_mode: row.payout_mode as PayoutMode,
    fee_profile_id: row.fee_profile_id || undefined,
    status: row.status,
    onboarding_status: row.onboarding_status,
    created_at: row.created_at,
    updated_at: row.updated_at
  };
}

export async function createMerchant(payload: {
  legal_name: string;
  brand_name?: string;
  settlement_account_reference?: string;
  settlement_account_type?: string;
  payout_mode?: PayoutMode;
  fee_profile_id?: string;
  status?: MerchantEntity["status"];
  onboarding_status?: MerchantEntity["onboarding_status"];
}): Promise<MerchantEntity> {
  const id = randomUUID();
  const now = nowIso();
  const payoutMode: PayoutMode = payload.payout_mode || "merchant_direct";

  const { rows } = await getPool().query(
    `INSERT INTO merchants (
      id,
      merchant_code,
      legal_name,
      brand_name,
      settlement_account_reference,
      settlement_account_type,
      payout_mode,
      fee_profile_id,
      status,
      onboarding_status,
      created_at,
      updated_at
    ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)
    RETURNING *`,
    [
      id,
      makeCode(id),
      payload.legal_name,
      payload.brand_name,
      payload.settlement_account_reference,
      payload.settlement_account_type,
      payoutMode,
      payload.fee_profile_id,
      payload.status || "active",
      payload.onboarding_status || "pending",
      now,
      now
    ]
  );

  return toPublic(mapRowToMerchant(rows[0]));
}

export async function getMerchantById(id: string): Promise<MerchantEntity | null> {
  const { rows } = await getPool().query("SELECT * FROM merchants WHERE id = $1", [id]);
  if (rows.length === 0) {
    return null;
  }
  return mapRowToMerchant(rows[0]);
}

export async function getMerchantByCode(code: string): Promise<MerchantEntity | null> {
  const { rows } = await getPool().query("SELECT * FROM merchants WHERE merchant_code = $1", [code]);
  if (rows.length === 0) {
    return null;
  }
  return mapRowToMerchant(rows[0]);
}

export async function listMerchants(): Promise<MerchantEntity[]> {
  const { rows } = await getPool().query("SELECT * FROM merchants ORDER BY created_at DESC");
  return rows.map(mapRowToMerchant);
}

export async function patchMerchant(
  id: string,
  patch: {
    legal_name?: string;
    brand_name?: string;
    settlement_account_reference?: string;
    settlement_account_type?: string;
    payout_mode?: PayoutMode;
    fee_profile_id?: string;
    status?: MerchantEntity["status"];
    onboarding_status?: MerchantEntity["onboarding_status"];
  }
): Promise<MerchantEntity> {
  const existing = await getMerchantById(id);
  if (!existing) {
    throw new Error("MERCHANT_NOT_FOUND");
  }

  const merged = { ...existing, ...patch, updated_at: nowIso() };

  const { rows } = await getPool().query(
    `UPDATE merchants
       SET legal_name = $2,
           brand_name = $3,
           settlement_account_reference = $4,
           settlement_account_type = $5,
           payout_mode = $6,
           fee_profile_id = $7,
           status = $8,
           onboarding_status = $9,
           updated_at = $10
     WHERE id = $1
     RETURNING *`,
    [
      id,
      merged.legal_name,
      merged.brand_name,
      merged.settlement_account_reference,
      merged.settlement_account_type,
      merged.payout_mode,
      merged.fee_profile_id,
      merged.status,
      merged.onboarding_status,
      merged.updated_at
    ]
  );

  return mapRowToMerchant(rows[0]);
}

export function toMerchantPayload(m: MerchantEntity) {
  return {
    id: m.id,
    merchant_code: m.merchant_code,
    legal_name: m.legal_name,
    brand_name: m.brand_name,
    settlement_account_reference: m.settlement_account_reference,
    settlement_account_type: m.settlement_account_type,
    payout_mode: m.payout_mode,
    fee_profile_id: m.fee_profile_id,
    status: m.status,
    onboarding_status: m.onboarding_status,
    created_at: m.created_at,
    updated_at: m.updated_at
  };
}
