import { DepartmentKey, Prisma, WorkspaceConfigStatus } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import type {
  HumanCapitalFileRequirementDTO,
  HumanCapitalWorkspaceTabConfig,
  HumanCapitalWorkspaceTabKey,
  HumanCapitalWorkspaceVersion,
} from "@/lib/human-capital/types";

const DEFAULT_WORKSPACE_TABS: HumanCapitalWorkspaceTabConfig[] = [
  {
    key: "resumen",
    label: "Resumen",
    description: "Score, tendencias y vision general de Capital Humano.",
    order: 0,
    visible: true,
    widgets: ["summary_metrics"],
  },
  {
    key: "expedientes",
    label: "Expedientes",
    description: "Checklist de documentos por persona y estatus de completitud.",
    order: 1,
    visible: true,
    widgets: ["people_files_table"],
  },
  {
    key: "nomina",
    label: "Nomina",
    description: "Percepciones, deducciones y aportaciones por periodo y ubicacion.",
    order: 2,
    visible: true,
    widgets: ["payroll_summary"],
  },
  {
    key: "reclutamiento",
    label: "Reclutamiento",
    description: "Headcount actual, vacantes y organizacion ideal por sucursal/rol.",
    order: 3,
    visible: true,
    widgets: ["recruitment_headcount", "recruitment_vacancies", "recruitment_org_target"],
  },
  {
    key: "desarrollo",
    label: "Desarrollo",
    description: "Anuncios internos y cursos para crecimiento de carrera.",
    order: 4,
    visible: true,
    widgets: ["career_feed"],
  },
  {
    key: "cumplimiento",
    label: "Cumplimiento",
    description: "IMSS, Infonavit, Fonacot y seguimiento de pagos.",
    order: 5,
    visible: true,
    widgets: ["compliance_overview"],
  },
];

const DEFAULT_FILE_REQUIREMENTS: Array<
  Pick<HumanCapitalFileRequirementDTO, "key" | "label" | "fieldType" | "isRequired" | "sortOrder"> & {
    description?: string;
  }
> = [
  { key: "curp", label: "CURP", fieldType: "document", isRequired: true, sortOrder: 10 },
  { key: "ine", label: "INE", fieldType: "document", isRequired: true, sortOrder: 20 },
  {
    key: "comprobante_domicilio",
    label: "Comprobante de domicilio",
    fieldType: "document",
    isRequired: true,
    sortOrder: 30,
  },
  { key: "imss", label: "Numero IMSS", fieldType: "text", isRequired: true, sortOrder: 40 },
  { key: "nss", label: "NSS", fieldType: "text", isRequired: true, sortOrder: 50 },
  { key: "email", label: "Email", fieldType: "email", isRequired: true, sortOrder: 60 },
  { key: "phone", label: "Telefono", fieldType: "phone", isRequired: true, sortOrder: 70 },
];

function isTabKey(value: string): value is HumanCapitalWorkspaceTabKey {
  return ["resumen", "expedientes", "nomina", "reclutamiento", "desarrollo", "cumplimiento"].includes(value);
}

function parseTabs(raw: Prisma.JsonValue): HumanCapitalWorkspaceTabConfig[] {
  if (!Array.isArray(raw)) {
    return DEFAULT_WORKSPACE_TABS;
  }

  const parsed = raw
    .map((entry, idx): HumanCapitalWorkspaceTabConfig | null => {
      if (!entry || typeof entry !== "object") {
        return null;
      }

      const value = entry as Record<string, unknown>;
      const key = typeof value.key === "string" ? value.key : "";
      if (!isTabKey(key)) {
        return null;
      }

      const label = typeof value.label === "string" && value.label.trim().length > 0 ? value.label.trim() : key;
      const description = typeof value.description === "string" ? value.description.trim() : "";
      const order = Number.isFinite(value.order) ? Number(value.order) : idx;
      const visible = typeof value.visible === "boolean" ? value.visible : true;
      const widgets = Array.isArray(value.widgets)
        ? value.widgets.filter((widget): widget is HumanCapitalWorkspaceTabConfig["widgets"][number] => {
            return (
              typeof widget === "string" &&
              [
                "summary_metrics",
                "people_files_table",
                "payroll_summary",
                "recruitment_headcount",
                "recruitment_vacancies",
                "recruitment_org_target",
                "career_feed",
                "compliance_overview",
              ].includes(widget)
            );
          })
        : [];

      return {
        key,
        label,
        description: description || undefined,
        order,
        visible,
        widgets,
      };
    })
    .filter((entry): entry is HumanCapitalWorkspaceTabConfig => Boolean(entry));

  if (parsed.length === 0) {
    return DEFAULT_WORKSPACE_TABS;
  }

  return parsed.sort((a, b) => a.order - b.order);
}

export function validateWorkspaceTabs(input: unknown): HumanCapitalWorkspaceTabConfig[] {
  if (!Array.isArray(input)) {
    throw new Error("tabs must be an array.");
  }

  const sanitized = parseTabs(input as Prisma.JsonValue);
  if (sanitized.length === 0) {
    throw new Error("At least one valid tab is required.");
  }

  const keys = new Set<string>();
  for (const tab of sanitized) {
    if (keys.has(tab.key)) {
      throw new Error(`Duplicate tab key: ${tab.key}`);
    }
    keys.add(tab.key);
  }

  return sanitized;
}

function mapVersion(record: {
  id: string;
  department: DepartmentKey;
  version: number;
  status: WorkspaceConfigStatus;
  name: string;
  tabs: Prisma.JsonValue;
  changeSummary: string | null;
  createdById: string | null;
  publishedById: string | null;
  publishedAt: Date | null;
  createdAt: Date;
  updatedAt: Date;
}): HumanCapitalWorkspaceVersion {
  return {
    id: record.id,
    department: "capital_humano",
    version: record.version,
    status: record.status,
    name: record.name,
    tabs: parseTabs(record.tabs),
    changeSummary: record.changeSummary,
    createdById: record.createdById,
    publishedById: record.publishedById,
    publishedAt: record.publishedAt ? record.publishedAt.toISOString() : null,
    createdAt: record.createdAt.toISOString(),
    updatedAt: record.updatedAt.toISOString(),
  };
}

export async function ensureHumanCapitalWorkspaceBootstrap() {
  const existingPublished = await prisma.hrWorkspaceConfigVersion.findFirst({
    where: {
      department: DepartmentKey.capital_humano,
      status: WorkspaceConfigStatus.published,
    },
    orderBy: { version: "desc" },
  });

  if (!existingPublished) {
    await prisma.hrWorkspaceConfigVersion.create({
      data: {
        department: DepartmentKey.capital_humano,
        version: 1,
        status: WorkspaceConfigStatus.published,
        tabs: DEFAULT_WORKSPACE_TABS as unknown as Prisma.InputJsonValue,
        name: "Capital Humano Workspace",
        publishedAt: new Date(),
      },
    });
  }

  for (const requirement of DEFAULT_FILE_REQUIREMENTS) {
    await prisma.hrFileRequirement.upsert({
      where: {
        department_key: {
          department: DepartmentKey.capital_humano,
          key: requirement.key,
        },
      },
      update: {
        label: requirement.label,
        fieldType: requirement.fieldType,
        isRequired: requirement.isRequired,
        sortOrder: requirement.sortOrder,
      },
      create: {
        department: DepartmentKey.capital_humano,
        key: requirement.key,
        label: requirement.label,
        description: requirement.description,
        fieldType: requirement.fieldType,
        isRequired: requirement.isRequired,
        sortOrder: requirement.sortOrder,
      },
    });
  }
}

async function ensureDraftVersion(actorId?: string | null) {
  await ensureHumanCapitalWorkspaceBootstrap();

  const existingDraft = await prisma.hrWorkspaceConfigVersion.findFirst({
    where: {
      department: DepartmentKey.capital_humano,
      status: WorkspaceConfigStatus.draft,
    },
    orderBy: { version: "desc" },
  });

  if (existingDraft) {
    return existingDraft;
  }

  const latestVersion = await prisma.hrWorkspaceConfigVersion.findFirst({
    where: { department: DepartmentKey.capital_humano },
    orderBy: { version: "desc" },
  });

  if (!latestVersion) {
    throw new Error("Unable to bootstrap Human Capital workspace draft.");
  }

  return prisma.hrWorkspaceConfigVersion.create({
    data: {
      department: DepartmentKey.capital_humano,
      version: latestVersion.version + 1,
      status: WorkspaceConfigStatus.draft,
      tabs: latestVersion.tabs as Prisma.InputJsonValue,
      createdById: actorId ?? null,
      name: latestVersion.name,
    },
  });
}

export async function getHumanCapitalWorkspaceConfig(input?: { mode?: "published" | "draft"; actorId?: string | null }) {
  const mode = input?.mode ?? "published";

  if (mode === "draft") {
    const draft = await ensureDraftVersion(input?.actorId ?? null);
    return mapVersion(draft);
  }

  await ensureHumanCapitalWorkspaceBootstrap();

  const published = await prisma.hrWorkspaceConfigVersion.findFirst({
    where: {
      department: DepartmentKey.capital_humano,
      status: WorkspaceConfigStatus.published,
    },
    orderBy: { version: "desc" },
  });

  if (!published) {
    throw new Error("No published Human Capital workspace found.");
  }

  return mapVersion(published);
}

export async function updateHumanCapitalWorkspaceDraft(input: {
  tabs: unknown;
  actorId?: string | null;
  changeSummary?: string | null;
}) {
  const tabs = validateWorkspaceTabs(input.tabs);
  const draft = await ensureDraftVersion(input.actorId ?? null);

  const updated = await prisma.hrWorkspaceConfigVersion.update({
    where: { id: draft.id },
    data: {
      tabs: tabs as unknown as Prisma.InputJsonValue,
      changeSummary: input.changeSummary?.trim() || null,
      createdById: input.actorId ?? draft.createdById,
    },
  });

  return mapVersion(updated);
}

export async function publishHumanCapitalWorkspaceDraft(actorId: string) {
  const draft = await prisma.hrWorkspaceConfigVersion.findFirst({
    where: {
      department: DepartmentKey.capital_humano,
      status: WorkspaceConfigStatus.draft,
    },
    orderBy: { version: "desc" },
  });

  if (!draft) {
    throw new Error("No draft workspace version available to publish.");
  }

  const published = await prisma.$transaction(async (tx) => {
    await tx.hrWorkspaceConfigVersion.updateMany({
      where: {
        department: DepartmentKey.capital_humano,
        status: WorkspaceConfigStatus.published,
      },
      data: {
        status: WorkspaceConfigStatus.archived,
      },
    });

    return tx.hrWorkspaceConfigVersion.update({
      where: { id: draft.id },
      data: {
        status: WorkspaceConfigStatus.published,
        publishedById: actorId,
        publishedAt: new Date(),
      },
    });
  });

  return mapVersion(published);
}

export async function listHumanCapitalWorkspaceHistory() {
  await ensureHumanCapitalWorkspaceBootstrap();

  const versions = await prisma.hrWorkspaceConfigVersion.findMany({
    where: {
      department: DepartmentKey.capital_humano,
    },
    orderBy: [{ version: "desc" }],
    take: 40,
  });

  return versions.map(mapVersion);
}
