import type { ResultSetHeader, RowDataPacket } from "mysql2/promise";
import { pool } from "../db/mysql.js";
import { decryptNullable, encryptNullable } from "../crypto/secretbox.js";
import type { Exchange } from "../exchange/types.js";

/** Repositório de contrapartes/clientes (`counterparties`). PII criptografada. */

export interface CounterpartyRow extends RowDataPacket {
  id: number;
  exchange: Exchange;
  counterparty_ref: string;
  display_name: string | null;
  cpf_enc: Buffer | null;
  phone_enc: Buffer | null;
  pix_key_enc: Buffer | null;
  validated: number;
  total_orders: number;
}

/** Dados pessoais decifrados (uso interno/administrativo, LGPD). */
export interface CounterpartyPII {
  cpf: string | null;
  phone: string | null;
  pixKey: string | null;
}

/** Garante a existência da contraparte; devolve o id. Atualiza o nome. */
export async function upsertCounterparty(
  exchange: Exchange,
  ref: string,
  displayName: string | null,
): Promise<CounterpartyRow> {
  await pool.query(
    `INSERT INTO counterparties (exchange, counterparty_ref, display_name, first_order_at)
     VALUES (:exchange, :ref, :displayName, NOW())
     ON DUPLICATE KEY UPDATE
       display_name = COALESCE(VALUES(display_name), display_name)`,
    { exchange, ref, displayName },
  );
  const [rows] = await pool.query<CounterpartyRow[]>(
    `SELECT * FROM counterparties WHERE exchange = :exchange AND counterparty_ref = :ref`,
    { exchange, ref },
  );
  return rows[0];
}

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

export async function list(): Promise<CounterpartyRow[]> {
  const [rows] = await pool.query<CounterpartyRow[]>(
    `SELECT * FROM counterparties ORDER BY updated_at DESC`,
  );
  return rows;
}

export function decryptPII(row: CounterpartyRow): CounterpartyPII {
  return {
    cpf: decryptNullable(row.cpf_enc),
    phone: decryptNullable(row.phone_enc),
    pixKey: decryptNullable(row.pix_key_enc),
  };
}

/** Marca a contraparte como validada e grava os dados pessoais (cripto). */
export async function setValidated(
  id: number,
  pii: Partial<CounterpartyPII>,
): Promise<void> {
  await pool.query<ResultSetHeader>(
    `UPDATE counterparties
        SET validated = 1, validated_at = NOW(),
            cpf_enc = COALESCE(:cpf, cpf_enc),
            phone_enc = COALESCE(:phone, phone_enc),
            pix_key_enc = COALESCE(:pix, pix_key_enc)
      WHERE id = :id`,
    {
      id,
      cpf: encryptNullable(pii.cpf ?? null),
      phone: encryptNullable(pii.phone ?? null),
      pix: encryptNullable(pii.pixKey ?? null),
    },
  );
}

export async function incrementOrders(id: number): Promise<void> {
  await pool.query(
    `UPDATE counterparties SET total_orders = total_orders + 1 WHERE id = :id`,
    { id },
  );
}
