import { SystemRole } from "@capakraken/shared";
import { describe, expect, it, vi } from "vitest";

const { createAuditEntry } = vi.hoisted(() => ({
  createAuditEntry: vi.fn(),
}));

vi.mock("../lib/audit.js", () => ({
  createAuditEntry,
}));

vi.mock("@capakraken/engine", () => ({
  applyExperienceMultipliers: vi.fn().mockReturnValue({
    adjustedCostRateCents: 12_000,
    adjustedBillRateCents: 18_000,
    adjustedHours: 110,
    appliedRules: ["Rate multiplied (chapter=VFX): cost x1.2, bill x1.2"],
  }),
  applyExperienceMultipliersBatch: vi.fn().mockReturnValue({
    results: [
      {
        adjustedCostRateCents: 12_000,
        adjustedBillRateCents: 18_000,
        adjustedHours: 110,
        appliedRules: ["Rate multiplied (chapter=VFX): cost x1.2, bill x1.2"],
      },
    ],
    totalOriginalHours: 100,
    totalAdjustedHours: 110,
    linesAdjusted: 1,
  }),
}));

import {
  applyExperienceMultiplierRules,
  createExperienceMultiplierSet,
  previewExperienceMultipliers,
} from "../router/experience-multiplier-procedure-support.js";

function createManagerContext(db: Record<string, unknown>) {
  return {
    db: db as never,
    dbUser: {
      id: "user_mgr",
      systemRole: SystemRole.MANAGER,
      permissionOverrides: null,
    },
  };
}

function createControllerContext(db: Record<string, unknown>) {
  return {
    db: db as never,
    dbUser: {
      id: "user_ctrl",
      systemRole: SystemRole.CONTROLLER,
      permissionOverrides: null,
    },
  };
}

function sampleMultiplierSet(overrides: Record<string, unknown> = {}) {
  return {
    id: "ems_1",
    name: "Standard Multipliers",
    description: null,
    isDefault: true,
    createdAt: new Date(),
    updatedAt: new Date(),
    rules: [
      {
        id: "emr_1",
        multiplierSetId: "ems_1",
        chapter: "VFX",
        location: null,
        level: null,
        costMultiplier: 1.2,
        billMultiplier: 1.2,
        shoringRatio: null,
        additionalEffortRatio: null,
        description: null,
        sortOrder: 0,
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    ],
    ...overrides,
  };
}

describe("experience multiplier procedure support", () => {
  it("creates a multiplier set and audits it", async () => {
    const create = vi.fn().mockResolvedValue(sampleMultiplierSet());
    const updateMany = vi.fn().mockResolvedValue({ count: 1 });

    const result = await createExperienceMultiplierSet(createManagerContext({
      experienceMultiplierSet: {
        updateMany,
        create,
      },
    }), {
      name: "Standard Multipliers",
      description: "Default",
      isDefault: true,
      rules: [],
    });

    expect(updateMany).toHaveBeenCalledWith({
      where: { isDefault: true },
      data: { isDefault: false },
    });
    expect(create).toHaveBeenCalledWith(expect.objectContaining({
      data: expect.objectContaining({
        name: "Standard Multipliers",
        isDefault: true,
      }),
    }));
    expect(createAuditEntry).toHaveBeenCalledWith(expect.objectContaining({
      entityType: "ExperienceMultiplierSet",
      action: "CREATE",
      entityId: result.id,
    }));
  });

  it("previews adjusted demand lines for the latest estimate version", async () => {
    const result = await previewExperienceMultipliers(createControllerContext({
      estimate: {
        findUnique: vi.fn().mockResolvedValue({
          id: "est_1",
          versions: [
            {
              id: "v_1",
              versionNumber: 2,
              demandLines: [
                {
                  id: "dl_1",
                  name: "Compositing Senior",
                  chapter: "VFX",
                  costRateCents: 10_000,
                  billRateCents: 15_000,
                  hours: 100,
                  metadata: null,
                  staffingAttributes: null,
                },
              ],
            },
          ],
        }),
      },
      experienceMultiplierSet: {
        findUnique: vi.fn().mockResolvedValue(sampleMultiplierSet()),
      },
    }), {
      estimateId: "est_1",
      multiplierSetId: "ems_1",
    });

    expect(result.demandLineCount).toBe(1);
    expect(result.linesChanged).toBe(1);
    expect(result.totalOriginalCostCents).toBe(1_000_000);
    expect(result.totalAdjustedCostCents).toBe(1_320_000);
  });

  it("updates changed demand lines and audits estimate updates", async () => {
    const update = vi.fn().mockResolvedValue({});
    const auditCreate = vi.fn().mockResolvedValue({});

    const result = await applyExperienceMultiplierRules(createManagerContext({
      estimate: {
        findUnique: vi.fn().mockResolvedValue({
          id: "est_1",
          versions: [
            {
              id: "v_1",
              versionNumber: 2,
              status: "WORKING",
              demandLines: [
                {
                  id: "dl_1",
                  name: "Compositing Senior",
                  chapter: "VFX",
                  costRateCents: 10_000,
                  billRateCents: 15_000,
                  hours: 100,
                  metadata: null,
                  staffingAttributes: null,
                },
              ],
            },
          ],
        }),
      },
      experienceMultiplierSet: {
        findUnique: vi.fn().mockResolvedValue(sampleMultiplierSet()),
      },
      estimateDemandLine: {
        update,
      },
      auditLog: {
        create: auditCreate,
      },
    }), {
      estimateId: "est_1",
      multiplierSetId: "ems_1",
    });

    expect(update).toHaveBeenCalledTimes(1);
    expect(auditCreate).toHaveBeenCalledTimes(1);
    expect(result).toEqual({
      linesUpdated: 1,
      totalOriginalHours: 100,
      totalAdjustedHours: 110,
    });
  });
});
