import { createHash } from "node:crypto";
import { AllocationType, OrderType } from "@capakraken/db";

function extractBracketTokens(token: string): string[] {
  return Array.from(
    token.matchAll(/\[([^\]]+)\]/g),
    (match) => match[1]?.trim() ?? "",
  ).filter(Boolean);
}

function extractClientCode(token: string): string | null {
  const candidates = extractBracketTokens(token).filter(
    (entry) =>
      entry.length > 0 &&
      !entry.startsWith("_") &&
      !/^\d+$/.test(entry) &&
      entry.toLowerCase() !== "tbd",
  );

  return candidates[0] ?? null;
}

function extractProjectLabel(token: string): string | null {
  const stripped = token
    .replace(/^(2D|3D|PM|AD)\s+/i, "")
    .replace(/\[[^\]]+\]/g, " ")
    .replace(/\{[^}]+\}/g, " ")
    .replace(/\s+(?:HB|SB)_?\s*$/i, " ")
    .replace(/\s+/g, " ")
    .trim();

  return stripped.length > 0 ? stripped : null;
}

function slugifyFragment(value: string): string {
  return value
    .toUpperCase()
    .replace(/[^A-Z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");
}

function shortSegment(value: string | null | undefined, fallback: string, maxLength: number): string {
  const normalized = slugifyFragment(value ?? "");
  return (normalized.length > 0 ? normalized : fallback).slice(0, maxLength);
}

export interface DerivedDispoProjectIdentity {
  clientCode: string | null;
  name: string;
  projectKey: string;
  shortCode: string;
}

export interface DerivedDispoProjectClassification {
  allocationType: AllocationType;
  orderType: OrderType;
}

export function classifyDispoProject(utilizationCategoryCode: string | null): DerivedDispoProjectClassification {
  if (utilizationCategoryCode === "Chg") {
    return {
      allocationType: AllocationType.EXT,
      orderType: OrderType.CHARGEABLE,
    };
  }

  if (utilizationCategoryCode === "BD") {
    return {
      allocationType: AllocationType.INT,
      orderType: OrderType.BD,
    };
  }

  return {
    allocationType: AllocationType.INT,
    orderType: OrderType.INTERNAL,
  };
}

export function deriveResolvedDispoProjectIdentity(
  rawToken: string,
  fallbackProjectKey: string,
): DerivedDispoProjectIdentity {
  const name = extractProjectLabel(rawToken) ?? `Project ${fallbackProjectKey}`;

  return {
    clientCode: extractClientCode(rawToken),
    name,
    projectKey: fallbackProjectKey,
    shortCode: fallbackProjectKey,
  };
}

export function deriveTbdDispoProjectIdentity(
  rawToken: string,
  utilizationCategoryCode: string | null,
): DerivedDispoProjectIdentity {
  const clientCode = extractClientCode(rawToken);
  const name = extractProjectLabel(rawToken) ?? "Unresolved Dispo Work";
  const clientSegment = shortSegment(clientCode, "GEN", 10);
  const utilizationSegment = shortSegment(utilizationCategoryCode, "UNK", 6);
  const labelSegment = shortSegment(name, "UNRESOLVED-WORK", 24);
  const hash = createHash("sha1")
    .update(`${rawToken.trim().toLowerCase()}|${utilizationCategoryCode ?? ""}`)
    .digest("hex")
    .slice(0, 8)
    .toUpperCase();
  const shortCode = `TBD-${clientSegment}-${utilizationSegment}-${labelSegment}-${hash}`;

  return {
    clientCode,
    name: `TBD: ${name}`,
    projectKey: shortCode,
    shortCode,
  };
}
