import { screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi, beforeEach } from "vitest";
import CampaignsSettings from "./CampaignsSettings";
import { renderWithQueryClient as render } from "../reports/test-utils";
import { CommissionConfigurationAPI } from "@/apis/CommissionConfigurationAPI";
import { CampaignAttributionConfigurationAPI } from "@/apis/CampaignsAPI";
import { ReportsAPI } from "@/apis/ReportsAPI";
import { toast } from "sonner";

vi.mock("@/apis/CommissionConfigurationAPI", () => ({
  CommissionConfigurationAPI: { getPrimaryCompanyForCurrentUser: vi.fn() },
}));

vi.mock("@/apis/CampaignsAPI", () => ({
  CampaignAttributionConfigurationAPI: { get: vi.fn(), save: vi.fn() },
}));

vi.mock("@/apis/ReportsAPI", () => ({
  ReportsAPI: {
    getReactivationBonusConfiguration: vi.fn(),
    saveReactivationBonusConfiguration: vi.fn(),
    runReactivationBonus: vi.fn(),
  },
}));

vi.mock("sonner", () => ({
  toast: { success: vi.fn(), error: vi.fn() },
}));

describe("CampaignsSettings", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    CampaignAttributionConfigurationAPI.get.mockResolvedValue({
      idcompany: 1,
      attribution_window_days: 30,
      roi_horizon_months: 3,
      volume_uses_net: true,
      is_active: true,
    });
    ReportsAPI.getReactivationBonusConfiguration.mockResolvedValue({
      idcompany: 1,
      bonus_type: "percentage",
      bonus_value: 5,
      min_inactive_days: 30,
      min_sale_amount: 0,
      is_active: true,
    });
  });

  it("muestra mensaje cuando no hay empresa seleccionada", async () => {
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue(null);
    render(<CampaignsSettings />);
    expect(await screen.findByText(/No se encontró empresa seleccionada/i)).toBeInTheDocument();
  });

  it("carga y muestra la configuración de atribución y del bono de reactivación", async () => {
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });
    render(<CampaignsSettings />);

    expect(await screen.findByText(/Atribución de ventas y ROI diferido/i)).toBeInTheDocument();
    expect(screen.getByText(/Bono de reactivación/i)).toBeInTheDocument();
    await waitFor(() => expect(screen.getByLabelText(/Ventana de atribución/i)).toHaveValue(30));
  });

  it("guarda la configuración de atribución al enviar el formulario", async () => {
    const user = userEvent.setup();
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });
    CampaignAttributionConfigurationAPI.save.mockResolvedValue({});

    render(<CampaignsSettings />);
    await screen.findByText(/Atribución de ventas y ROI diferido/i);

    await user.click(screen.getByRole("button", { name: /Guardar configuración de atribución/i }));
    await waitFor(() => expect(CampaignAttributionConfigurationAPI.save).toHaveBeenCalled());
    expect(toast.success).toHaveBeenCalled();
  });

  it("guarda la configuración del bono y ejecuta la corrida del mes", async () => {
    const user = userEvent.setup();
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });
    ReportsAPI.saveReactivationBonusConfiguration.mockResolvedValue({});
    ReportsAPI.runReactivationBonus.mockResolvedValue({});

    render(<CampaignsSettings />);
    await screen.findByText(/Bono de reactivación/i);

    await user.click(screen.getByRole("button", { name: /Guardar configuración del bono/i }));
    await waitFor(() => expect(ReportsAPI.saveReactivationBonusConfiguration).toHaveBeenCalled());

    await user.click(screen.getByRole("button", { name: /Ejecutar corrida del mes/i }));
    await waitFor(() => expect(ReportsAPI.runReactivationBonus).toHaveBeenCalledWith(1));
    expect(toast.success).toHaveBeenCalled();
  });

  it("muestra error si falla al cargar la empresa", async () => {
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockRejectedValue(new Error("fail"));
    render(<CampaignsSettings />);
    await waitFor(() => expect(toast.error).toHaveBeenCalled());
  });

  it("permite editar los campos de atribución y alternar el checkbox de volumen neto", async () => {
    const user = userEvent.setup();
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });

    render(<CampaignsSettings />);
    const windowInput = await screen.findByLabelText(/Ventana de atribución/i);
    await waitFor(() => expect(windowInput).toHaveValue(30));

    await user.clear(windowInput);
    await user.type(windowInput, "45");
    expect(windowInput).toHaveValue(45);

    const horizonInput = screen.getByLabelText(/Horizonte de ROI/i);
    await user.clear(horizonInput);
    await user.type(horizonInput, "6");
    expect(horizonInput).toHaveValue(6);

    const netCheckbox = screen.getByLabelText(/Usar volumen neto/i);
    expect(netCheckbox).toBeChecked();
    await user.click(netCheckbox);
    expect(netCheckbox).not.toBeChecked();
  });

  it("cambia el tipo de bono a monto fijo y edita los campos numéricos", async () => {
    const user = userEvent.setup();
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });

    render(<CampaignsSettings />);
    await screen.findByText(/Bono de reactivación/i);

    await user.click(screen.getByRole("combobox"));
    await user.click(screen.getByRole("option", { name: "Monto fijo" }));
    expect(await screen.findByText(/Monto fijo del bono/i)).toBeInTheDocument();

    const valueInput = screen.getByLabelText(/Monto fijo del bono/i);
    await user.clear(valueInput);
    await user.type(valueInput, "1500");
    expect(valueInput).toHaveValue(1500);

    const minDaysInput = screen.getByLabelText(/Días mínimos de inactividad/i);
    await user.clear(minDaysInput);
    await user.type(minDaysInput, "60");
    expect(minDaysInput).toHaveValue(60);

    const minSaleInput = screen.getByLabelText(/Monto mínimo de venta/i);
    await user.clear(minSaleInput);
    await user.type(minSaleInput, "5000");
    expect(minSaleInput).toHaveValue(5000);
  });

  it("muestra error si falla al guardar la configuración de atribución", async () => {
    const user = userEvent.setup();
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });
    CampaignAttributionConfigurationAPI.save.mockRejectedValue(new Error("fail"));

    render(<CampaignsSettings />);
    await screen.findByText(/Atribución de ventas y ROI diferido/i);
    await user.click(screen.getByRole("button", { name: /Guardar configuración de atribución/i }));

    await waitFor(() => expect(toast.error).toHaveBeenCalled());
  });

  it("muestra error si falla al guardar o ejecutar el bono de reactivación", async () => {
    const user = userEvent.setup();
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });
    ReportsAPI.saveReactivationBonusConfiguration.mockRejectedValue(new Error("fail"));
    ReportsAPI.runReactivationBonus.mockRejectedValue(new Error("fail"));

    render(<CampaignsSettings />);
    await screen.findByText(/Bono de reactivación/i);

    await user.click(screen.getByRole("button", { name: /Guardar configuración del bono/i }));
    await waitFor(() => expect(toast.error).toHaveBeenCalledTimes(1));

    await user.click(screen.getByRole("button", { name: /Ejecutar corrida del mes/i }));
    await waitFor(() => expect(toast.error).toHaveBeenCalledTimes(2));
  });

  it("no rompe cuando la configuración remota viene vacía (usa valores por defecto)", async () => {
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });
    CampaignAttributionConfigurationAPI.get.mockResolvedValue(null);
    ReportsAPI.getReactivationBonusConfiguration.mockResolvedValue(null);

    render(<CampaignsSettings />);
    const windowInput = await screen.findByLabelText(/Ventana de atribución/i);
    expect(windowInput).toHaveValue(30);
  });

  it("usa los valores por defecto cuando la configuración remota trae campos vacíos", async () => {
    CommissionConfigurationAPI.getPrimaryCompanyForCurrentUser.mockResolvedValue({ id: 1, name: "Softnet" });
    CampaignAttributionConfigurationAPI.get.mockResolvedValue({ idcompany: 1 });
    ReportsAPI.getReactivationBonusConfiguration.mockResolvedValue({ idcompany: 1 });

    render(<CampaignsSettings />);
    const windowInput = await screen.findByLabelText(/Ventana de atribución/i);
    await waitFor(() => expect(windowInput).toHaveValue(30));
    expect(screen.getByLabelText(/Horizonte de ROI/i)).toHaveValue(3);
    expect(screen.getByLabelText(/Días mínimos de inactividad/i)).toHaveValue(30);
  });
});
