import type { RowDataPacket } from "mysql2/promise";
import { pool } from "../db/mysql.js";
import type { OrderRecord } from "../exchange/types.js";

/** Repositório de ordens espelhadas (`orders`). */

export interface OrderRow extends RowDataPacket {
  id: number;
  account_id: number;
  order_no: string;
  adv_no: string | null;
  counterparty_id: number | null;
  trade_type: "BUY" | "SELL";
  asset: string;
  fiat: string;
  amount: string | null;
  total_price: string | null;
  order_status: number | null;
  status_text: string | null;
  asked_validation: number;
  asked_pix: number;
}

export interface UpsertOrderResult {
  id: number;
  /** true quando a ordem acabou de ser inserida (não existia). */
  isNew: boolean;
  askedValidation: boolean;
  askedPix: boolean;
}

export async function upsertOrder(
  accountId: number,
  order: OrderRecord,
  counterpartyId: number | null,
): Promise<UpsertOrderResult> {
  const before = await getByOrderNo(accountId, order.orderNo);
  await pool.query(
    `INSERT INTO orders
       (account_id, order_no, adv_no, counterparty_id, trade_type, asset, fiat,
        amount, total_price, order_status, status_text, payload_raw,
        order_created_at, synced_at)
     VALUES
       (:accountId, :orderNo, :advNo, :counterpartyId, :tradeType, :asset, :fiat,
        :amount, :totalPrice, :status, :statusText, CAST(:payload AS JSON),
        :createdAt, NOW())
     ON DUPLICATE KEY UPDATE
       adv_no = VALUES(adv_no),
       counterparty_id = COALESCE(VALUES(counterparty_id), counterparty_id),
       amount = VALUES(amount), total_price = VALUES(total_price),
       order_status = VALUES(order_status), status_text = VALUES(status_text),
       payload_raw = VALUES(payload_raw), synced_at = NOW()`,
    {
      accountId,
      orderNo: order.orderNo,
      advNo: order.advNo,
      counterpartyId,
      tradeType: order.tradeType,
      asset: order.asset,
      fiat: order.fiat,
      amount: order.amount,
      totalPrice: order.totalPrice,
      status: order.status,
      statusText: order.statusText,
      payload: JSON.stringify(order.raw ?? null),
      createdAt: order.createTime ? new Date(order.createTime) : null,
    },
  );
  const after = await getByOrderNo(accountId, order.orderNo);
  return {
    id: after?.id ?? 0,
    isNew: !before,
    askedValidation: !!after?.asked_validation,
    askedPix: !!after?.asked_pix,
  };
}

export async function getByOrderNo(
  accountId: number,
  orderNo: string,
): Promise<OrderRow | null> {
  const [rows] = await pool.query<OrderRow[]>(
    `SELECT * FROM orders WHERE account_id = :accountId AND order_no = :orderNo`,
    { accountId, orderNo },
  );
  return rows[0] ?? null;
}

export async function getById(id: number): Promise<OrderRow | null> {
  const [rows] = await pool.query<OrderRow[]>(`SELECT * FROM orders WHERE id = :id`, { id });
  return rows[0] ?? null;
}

export async function listOrders(accountId?: number): Promise<OrderRow[]> {
  if (accountId) {
    const [rows] = await pool.query<OrderRow[]>(
      `SELECT * FROM orders WHERE account_id = :accountId ORDER BY order_created_at DESC, id DESC`,
      { accountId },
    );
    return rows;
  }
  const [rows] = await pool.query<OrderRow[]>(
    `SELECT * FROM orders ORDER BY order_created_at DESC, id DESC LIMIT 500`,
  );
  return rows;
}

/** Marca a flag de automação já disparada (idempotência por ordem). */
export async function markAsked(id: number, which: "validation" | "pix"): Promise<void> {
  const col = which === "validation" ? "asked_validation" : "asked_pix";
  await pool.query(`UPDATE orders SET ${col} = 1 WHERE id = :id`, { id });
}
