import { describe, expect, it } from "vitest";
import {
  CommissionError,
  annulmentPayoutChanges,
  computeSaleSnapshot,
} from "@/lib/domain/commissions";

describe("computeSaleSnapshot — comisión del asesor (concepto B)", () => {
  it("sin comisión: monto 0 y sin estado", () => {
    const snapshot = computeSaleSnapshot({
      finalPrice: "24900",
      advisorCommission: { type: "NONE", value: "0" },
    });
    expect(snapshot.finalPrice).toBe("24900.00");
    expect(snapshot.advisorCommission).toEqual({
      type: "NONE",
      value: "0.00",
      amount: "0.00",
      status: null,
    });
    expect(snapshot.consignment).toBeNull();
  });

  it("porcentual: se calcula sobre el precio final y queda PENDING", () => {
    const snapshot = computeSaleSnapshot({
      finalPrice: "24900",
      advisorCommission: { type: "PERCENTAGE", value: "1.5" },
    });
    expect(snapshot.advisorCommission).toEqual({
      type: "PERCENTAGE",
      value: "1.50",
      amount: "373.50",
      status: "PENDING",
    });
  });

  it("porcentual: redondea al céntimo (half up)", () => {
    // 1 % de 0.50 = 0.005 → 0.01
    const snapshot = computeSaleSnapshot({
      finalPrice: "0.50",
      advisorCommission: { type: "PERCENTAGE", value: "1" },
    });
    expect(snapshot.advisorCommission.amount).toBe("0.01");
  });

  it("monto fijo", () => {
    const snapshot = computeSaleSnapshot({
      finalPrice: "24900",
      advisorCommission: { type: "FIXED", value: "300" },
    });
    expect(snapshot.advisorCommission.amount).toBe("300.00");
    expect(snapshot.advisorCommission.status).toBe("PENDING");
  });

  it("rechaza porcentaje mayor a 100", () => {
    expect(() =>
      computeSaleSnapshot({
        finalPrice: "1000",
        advisorCommission: { type: "PERCENTAGE", value: "100.01" },
      }),
    ).toThrow(CommissionError);
  });

  it("rechaza monto fijo mayor al precio", () => {
    try {
      computeSaleSnapshot({
        finalPrice: "1000",
        advisorCommission: { type: "FIXED", value: "1000.01" },
      });
      expect.unreachable();
    } catch (error) {
      expect(error).toBeInstanceOf(CommissionError);
      expect((error as CommissionError).code).toBe("FIXED_EXCEEDS_PRICE");
    }
  });

  it("rechaza montos con más de 2 decimales o negativos", () => {
    expect(() =>
      computeSaleSnapshot({
        finalPrice: "10.123",
        advisorCommission: { type: "NONE", value: "0" },
      }),
    ).toThrow(CommissionError);
    expect(() =>
      computeSaleSnapshot({ finalPrice: "-5", advisorCommission: { type: "NONE", value: "0" } }),
    ).toThrow(CommissionError);
  });
});

describe("computeSaleSnapshot — consignación (concepto A)", () => {
  it("neto al propietario = precio − comisión CHESCO; la comisión del asesor no se descuenta al propietario", () => {
    const snapshot = computeSaleSnapshot({
      finalPrice: "30000",
      advisorCommission: { type: "FIXED", value: "250" },
      consignment: { commission: { type: "PERCENTAGE", value: "5" }, minimumPrice: "28000" },
    });
    expect(snapshot.consignment).toEqual({
      chescoCommissionType: "PERCENTAGE",
      chescoCommissionValue: "5.00",
      chescoCommissionAmount: "1500.00",
      ownerPayoutAmount: "28500.00",
      ownerPayoutStatus: "PENDING",
      minimumPrice: "28000.00",
      belowMinimumPrice: false,
    });
    expect(snapshot.advisorCommission.amount).toBe("250.00");
  });

  it("marca la venta por debajo del precio mínimo", () => {
    const snapshot = computeSaleSnapshot({
      finalPrice: "27000",
      advisorCommission: { type: "NONE", value: "0" },
      consignment: { commission: { type: "FIXED", value: "1000" }, minimumPrice: "28000" },
    });
    expect(snapshot.consignment?.belowMinimumPrice).toBe(true);
    expect(snapshot.consignment?.ownerPayoutAmount).toBe("26000.00");
  });

  it("comisión CHESCO fija mayor al precio es un error", () => {
    expect(() =>
      computeSaleSnapshot({
        finalPrice: "1000",
        advisorCommission: { type: "NONE", value: "0" },
        consignment: { commission: { type: "FIXED", value: "2000" }, minimumPrice: null },
      }),
    ).toThrow(CommissionError);
  });
});

describe("annulmentPayoutChanges", () => {
  it("lo pendiente se cancela", () => {
    expect(
      annulmentPayoutChanges({ advisorCommissionStatus: "PENDING", ownerPayoutStatus: "PENDING" }),
    ).toEqual({
      advisorCommissionStatus: "CANCELLED",
      ownerPayoutStatus: "CANCELLED",
      requiresManualReview: false,
    });
  });

  it("lo ya pagado no se toca y pide revisión manual", () => {
    expect(
      annulmentPayoutChanges({ advisorCommissionStatus: "PAID", ownerPayoutStatus: null }),
    ).toEqual({
      advisorCommissionStatus: "PAID",
      ownerPayoutStatus: null,
      requiresManualReview: true,
    });
  });
});
