import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { INSERT_EMPLOYEE_TEAM, UPDATE_EMPLOYEE_TEAM } from "../../graphql/employee_teams.queries";
import { LABOR_TYPES } from "./shop-employee-teams.form.utils.js";
import { ShopEmployeeTeamsFormComponent } from "./shop-employee-teams.form.component.jsx";

const insertEmployeeTeamMock = vi.fn();
const updateEmployeeTeamMock = vi.fn();
const useQueryMock = vi.fn();
const useMutationMock = vi.fn();
const navigateMock = vi.fn();
const notification = {
  error: vi.fn(),
  success: vi.fn()
};

vi.mock("@apollo/client/react", () => ({
  useQuery: (...args) => useQueryMock(...args),
  useMutation: (...args) => useMutationMock(...args)
}));

vi.mock("react-router-dom", () => ({
  useLocation: () => ({
    search: "?employeeTeamId=new"
  }),
  useNavigate: () => navigateMock
}));

vi.mock("react-i18next", () => ({
  useTranslation: () => ({
    t: (key, values = {}) => {
      const translations = {
        "employee_teams.fields.name": "Team Name",
        "employee_teams.fields.active": "Active",
        "employee_teams.fields.max_load": "Max Load",
        "employee_teams.fields.employeeid": "Employee",
        "employee_teams.fields.allocation_percentage": "Allocation %",
        "employee_teams.fields.payout_method": "Payout Method",
        "employee_teams.fields.allocation": "Allocation",
        "employee_teams.fields.employeeid_label": "Employee",
        "employee_teams.options.hourly": "Hourly",
        "employee_teams.options.commission": "Commission",
        "employee_teams.options.commission_percentage": "Commission",
        "employee_teams.actions.newmember": "New Team Member",
        "employee_teams.actions.save_team": "Save Employee Team",
        "employee_teams.errors.minimum_one_member": "Add at least one team member.",
        "employee_teams.errors.duplicate_member": "Team members must be unique.",
        "employee_teams.errors.allocation_total_exact": "Allocation must total exactly 100%.",
        "general.labels.click_to_begin": `Click ${values.action ?? ""} to begin`,
        "general.actions.save": "Save",
        "employees.successes.save": "Saved"
      };

      if (key === "employee_teams.labels.allocation_total") {
        return `Allocation Total: ${values.total}%`;
      }

      if (key.startsWith("joblines.fields.lbr_types.")) {
        return key.split(".").pop();
      }

      return translations[key] || key;
    }
  })
}));

vi.mock("../../contexts/Notifications/notificationContext.jsx", () => ({
  useNotification: () => notification
}));

vi.mock("../form-fields-changed-alert/form-fields-changed-alert.component.jsx", () => ({
  default: () => null
}));

vi.mock("../../firebase/firebase.utils", () => ({
  logImEXEvent: vi.fn()
}));

vi.mock("../employee-search-select/employee-search-select.component", () => ({
  default: ({ id, value, onChange, options = [] }) => (
    <select
      aria-label="Employee"
      id={id}
      value={value ?? ""}
      onChange={(event) => onChange?.(event.target.value || undefined)}
    >
      <option value="">Select Employee</option>
      {options.map((option) => (
        <option key={option.id} value={option.id}>
          {[option.first_name, option.last_name].filter(Boolean).join(" ")}
        </option>
      ))}
    </select>
  )
}));

vi.mock("../form-items-formatted/currency-form-item.component", () => ({
  default: ({ id, value, onChange }) => (
    <input
      data-testid="currency-input"
      id={id}
      type="text"
      value={value ?? ""}
      onChange={(event) => onChange?.(event.target.value === "" ? null : Number(event.target.value))}
    />
  )
}));

vi.mock("../layout-form-row/layout-form-row.component", () => ({
  default: ({ title, extra, actions, children }) => (
    <div>
      {title}
      {extra}
      {children}
      {actions}
    </div>
  )
}));

vi.mock("../form-list-move-arrows/form-list-move-arrows.component", () => ({
  default: () => null
}));

const bodyshop = {
  id: "shop-1",
  employees: [
    {
      id: "emp-1",
      first_name: "Avery",
      last_name: "Johnson"
    },
    {
      id: "emp-2",
      first_name: "Morgan",
      last_name: "Lee"
    }
  ]
};

const fillHourlyRates = (value) => {
  LABOR_TYPES.forEach((laborType) => {
    fireEvent.change(screen.getByLabelText(laborType), {
      target: { value: String(value) }
    });
  });
};

const addBaseTeamMember = ({ employeeId = "emp-1", percentage = 100, rate = 25 } = {}) => {
  fireEvent.click(screen.getByRole("button", { name: "New Team Member" }));

  fireEvent.change(screen.getByLabelText("Employee"), {
    target: { value: employeeId }
  });
  fireEvent.change(screen.getByRole("spinbutton", { name: "Allocation" }), {
    target: { value: String(percentage) }
  });
  fillHourlyRates(rate);
};

describe("ShopEmployeeTeamsFormComponent", () => {
  beforeEach(() => {
    vi.clearAllMocks();

    useQueryMock.mockReturnValue({
      error: null,
      data: null,
      loading: false
    });

    useMutationMock.mockImplementation((mutation) => {
      if (mutation === UPDATE_EMPLOYEE_TEAM) {
        return [updateEmployeeTeamMock];
      }

      if (mutation === INSERT_EMPLOYEE_TEAM) {
        return [insertEmployeeTeamMock];
      }

      return [vi.fn()];
    });

    insertEmployeeTeamMock.mockResolvedValue({
      data: {
        insert_employee_teams_one: {
          id: "team-1"
        }
      }
    });
  });

  it("switches a new team member from hourly rates to commission percentages", async () => {
    render(<ShopEmployeeTeamsFormComponent bodyshop={bodyshop} />);

    addBaseTeamMember();
    expect(screen.getAllByTestId("currency-input")).toHaveLength(LABOR_TYPES.length);

    fireEvent.mouseDown(screen.getByRole("combobox", { name: "Payout Method" }));
    fireEvent.click(screen.getByText("Commission"));

    await waitFor(() => {
      expect(screen.queryAllByTestId("currency-input")).toHaveLength(0);
    });
  });

  it("submits a valid new hourly team with normalized member data", async () => {
    render(<ShopEmployeeTeamsFormComponent bodyshop={bodyshop} />);

    fireEvent.change(screen.getByRole("textbox", { name: "Team Name" }), {
      target: { value: "Commission Crew" }
    });
    fireEvent.change(screen.getByRole("spinbutton", { name: "Max Load" }), {
      target: { value: "8" }
    });

    addBaseTeamMember({
      employeeId: "emp-1",
      percentage: 100,
      rate: 27.5
    });

    fireEvent.click(screen.getByRole("button", { name: "Save Employee Team" }));

    await waitFor(() => {
      expect(insertEmployeeTeamMock).toHaveBeenCalledWith({
        variables: {
          employeeTeam: {
            name: "Commission Crew",
            max_load: 8,
            employee_team_members: {
              data: [
                {
                  employeeid: "emp-1",
                  percentage: 100,
                  payout_method: "hourly",
                  labor_rates: Object.fromEntries(LABOR_TYPES.map((laborType) => [laborType, 27.5])),
                  commission_rates: {}
                }
              ]
            },
            bodyshopid: "shop-1"
          }
        },
        refetchQueries: ["QUERY_TEAMS"]
      });
    });

    expect(notification.success).toHaveBeenCalledWith({
      title: "Saved"
    });
    expect(navigateMock).toHaveBeenCalledWith({
      search: "employeeTeamId=team-1"
    });
  });
});
