// ── Module Generator ─────────────────────────────────────────────────
// Generates missing internal modules from templates.
// Supports built-in templates and custom .setup-templates/ directory.
// Part of the self-healing setup pipeline — invoked when tsc reports
// TS2307 errors for @/ imports that don't exist yet.

import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, "..", "..");
const SETUP_TEMPLATES_DIR = path.join(ROOT, ".setup-templates");
const REGISTRY_PATH = path.join(SETUP_TEMPLATES_DIR, "registry.json");
const TEMPLATES_DIR = path.join(SETUP_TEMPLATES_DIR, "templates");

/** Maps internal import paths (e.g. "data/stickers") to their template file and optional params. */
export interface TemplateRegistry {
  [importPath: string]: {
    template: string;
    params?: Record<string, unknown>;
    generator?: string; // optional custom generator function name
  };
}

/** Result of a single module generation attempt. */
export interface GenerationResult {
  success: boolean;
  filePath: string;
  internalPath: string;
  message?: string;
  error?: string;
}

/** Maps glob patterns (e.g. "@/hooks/*") to fallback template file names. */
export interface FallbackRegistry {
  [pattern: string]: string;
}

/** Load the template registry from .setup-templates/registry.json, merging with built-in templates. */
export function loadRegistry(): { templates: TemplateRegistry; fallbacks: FallbackRegistry } {
  // Built-in mappings for the most commonly imported modules
  const builtInTemplates: TemplateRegistry = {
    "data/stickers": { template: "stickers.ts" },
    "data/constants": { template: "constants.ts" },
    "lib/utils": { template: "utils.ts" },
    "types/index": { template: "types-index.ts", params: { inferFromUsage: true } },
  };
  // Directory-level catch-all fallbacks for unknown imports
  const builtInFallbacks: FallbackRegistry = {
    "@/data/*": "data-generic.ts",
    "@/lib/*": "lib-generic.ts",
    "@/hooks/*": "hook-generic.ts",
    "@/types/*": "types-generic.ts",
    "@/components/*": "component-generic.tsx",
    "@/utils/*": "utils-generic.ts",
  };

  // Merge in any custom templates from the .setup-templates directory
  try {
    if (fs.existsSync(REGISTRY_PATH)) {
      const content = fs.readFileSync(REGISTRY_PATH, "utf-8");
      const custom = JSON.parse(content);
      return {
        templates: { ...builtInTemplates, ...(custom.templates || {}) },
        fallbacks: { ...builtInFallbacks, ...(custom.fallbackTemplates || {}) },
      };
    }
  } catch {
    // Use built-in
  }
  return { templates: builtInTemplates, fallbacks: builtInFallbacks };
}

/** Match an internal path (e.g. "data/stickers") against glob fallback patterns. Converts glob to regex internally. */
export function matchFallback(internalPath: string, fallbacks: FallbackRegistry): string | undefined {
  for (const [pattern, template] of Object.entries(fallbacks)) {
    // Convert glob pattern (e.g. "@/hooks/*") to a regular expression
    const regexStr = "^" + pattern
      .replace(/\//g, "\\/")
      .replace(/\./g, "\\.")
      .replace(/\*/g, ".*")
      .replace(/[$^+(){}[\]|]/g, "\\$&")
      + "$";
    const regex = new RegExp(regexStr);
    if (regex.test(internalPath)) {
      return template;
    }
  }
  return undefined;
}

/** Render a template string by replacing {{ paramName }} placeholders with actual values. */
function renderTemplate(templateContent: string, params: Record<string, unknown> = {}): string {
  let result = templateContent;
  for (const [key, value] of Object.entries(params)) {
    const regex = new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, "g");
    result = result.replace(regex, String(value));
  }
  return result;
}

/** Get template content — first tries the custom .setup-templates/templates dir, then falls back to built-in embedded templates. */
function getTemplateContent(templateName: string): string {
  // Check custom templates first
  const customPath = path.join(TEMPLATES_DIR, templateName);
  if (fs.existsSync(customPath)) {
    return fs.readFileSync(customPath, "utf-8");
  }

  // Built-in templates (embedded in the script — no external file needed)
  const builtInTemplates: Record<string, string> = {
    "stickers.ts": `// ── Sticker Packs ─────────────────────────────────────────────────
// Auto-generated by self-healing setup. Edit .setup-templates/templates/stickers.ts to customize.

export interface Sticker {
  id: string;
  name: string;
  emoji?: string;
  svg?: string;
}

export interface StickerPack {
  id: string;
  name: string;
  stickers: Sticker[];
}

export function getStickerPacks(): StickerPack[] {
  return [
    {
      id: "reactions",
      name: "Reactions",
      stickers: [
        { id: "thumbs-up", name: "Thumbs Up", emoji: "👍" },
        { id: "thumbs-down", name: "Thumbs Down", emoji: "👎" },
        { id: "heart", name: "Heart", emoji: "❤️" },
        { id: "laugh", name: "Laugh", emoji: "😂" },
        { id: "wow", name: "Wow", emoji: "😮" },
        { id: "sad", name: "Sad", emoji: "😢" },
        { id: "angry", name: "Angry", emoji: "😡" },
        { id: "clap", name: "Clap", emoji: "👏" },
        { id: "fire", name: "Fire", emoji: "🔥" },
        { id: "100", name: "100", emoji: "💯" },
        { id: "eyes", name: "Eyes", emoji: "👀" },
        { id: "pray", name: "Pray", emoji: "🙏" },
      ],
    },
    {
      id: "animals",
      name: "Animals",
      stickers: [
        { id: "cat", name: "Cat", emoji: "🐱" },
        { id: "dog", name: "Dog", emoji: "🐶" },
        { id: "panda", name: "Panda", emoji: "🐼" },
        { id: "fox", name: "Fox", emoji: "🦊" },
        { id: "bear", name: "Bear", emoji: "🐻" },
        { id: "koala", name: "Koala", emoji: "🐨" },
        { id: "tiger", name: "Tiger", emoji: "🐯" },
        { id: "lion", name: "Lion", emoji: "🦁" },
        { id: "monkey", name: "Monkey", emoji: "🐵" },
        { id: "frog", name: "Frog", emoji: "🐸" },
        { id: "penguin", name: "Penguin", emoji: "🐧" },
        { id: "bird", name: "Bird", emoji: "🐦" },
      ],
    },
    {
      id: "food",
      name: "Food & Drink",
      stickers: [
        { id: "pizza", name: "Pizza", emoji: "🍕" },
        { id: "burger", name: "Burger", emoji: "🍔" },
        { id: "taco", name: "Taco", emoji: "🌮" },
        { id: "sushi", name: "Sushi", emoji: "🍣" },
        { id: "ramen", name: "Ramen", emoji: "🍜" },
        { id: "ice-cream", name: "Ice Cream", emoji: "🍦" },
        { id: "cake", name: "Cake", emoji: "🎂" },
        { id: "coffee", name: "Coffee", emoji: "☕" },
        { id: "beer", name: "Beer", emoji: "🍺" },
        { id: "wine", name: "Wine", emoji: "🍷" },
        { id: "donut", name: "Donut", emoji: "🍩" },
        { id: "cookie", name: "Cookie", emoji: "🍪" },
      ],
    },
  ];
};

export function getStickerPacks(): StickerPack[] {
  return [
    // reactions, animals, food packs defined above
    // (inline for brevity - full packs in template file)
  ];
}
`,
    "constants.ts": `// ── App Constants ────────────────────────────────────────────────────
// Auto-generated by self-healing setup.

export const APP_NAME = "CoastIT CRM";
export const APP_VERSION = "1.0.0";

export const LEAD_STATUSES = {
  new: { label: "New", color: "bg-blue-500" },
  contacted: { label: "Contacted", color: "bg-yellow-500" },
  qualified: { label: "Qualified", color: "bg-purple-500" },
  proposal: { label: "Proposal", color: "bg-orange-500" },
  won: { label: "Won", color: "bg-green-500" },
  lost: { label: "Lost", color: "bg-red-500" },
} as const;

export const USER_ROLES = {
  super_admin: { label: "Super Admin", level: 1 },
  admin: { label: "Admin", level: 2 },
  sales: { label: "Sales", level: 3 },
  dev: { label: "Developer", level: 4 },
} as const;

export const EVENT_TYPES = [
  "meeting",
  "call",
  "email",
  "task",
  "note",
] as const;
`,
    "utils.ts": `// ── Utility Functions ────────────────────────────────────────────────
// Auto-generated by self-healing setup.

import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

export function formatDate(date: Date | string, options?: Intl.DateTimeFormatOptions): string {
  const d = typeof date === "string" ? new Date(date) : date;
  return d.toLocaleDateString("en-US", {
    year: "numeric",
    month: "short",
    day: "numeric",
    ...options,
  });
}

export function formatTime(date: Date | string): string {
  const d = typeof date === "string" ? new Date(date) : date;
  return d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", hour12: true });
}

export function formatCurrency(amount: number, currency = "USD"): string {
  return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
}

export function truncate(str: string, length: number): string {
  if (str.length <= length) return str;
  return str.slice(0, length - 3) + "...";
}

export function generateId(): string {
  return crypto.randomUUID();
}

export function debounce<T extends (...args: unknown[]) => unknown>(
  fn: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timeoutId: ReturnType<typeof setTimeout>;
  return (...args: Parameters<T>) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn(...args), delay);
  };
}
`,
    "types-index.ts": `// ── Type Definitions ──────────────────────────────────────────────────
// Auto-generated by self-healing setup.

export type UserRole = "super_admin" | "admin" | "sales" | "dev";

export interface User {
  id: string;
  name: string;
  email: string;
  phone?: string;
  role: UserRole;
  active: boolean;
  avatar: string;
  createdAt: string;
}

export interface Lead {
  id: string;
  companyName: string;
  contactName: string;
  email: string;
  phone: string;
  source: string;
  description: string;
  status: LeadStatus;
  assignedUserId: string | null;
  assignedUser: User | null;
  createdAt: string;
  updatedAt: string;
}

export type LeadStatus = "new" | "contacted" | "qualified" | "proposal" | "won" | "lost";

export interface DashboardStats {
  totalLeads: number;
  newLeads: number;
  contactedLeads: number;
  qualifiedLeads: number;
  proposalLeads: number;
  wonLeads: number;
  lostLeads: number;
  conversionRate: number;
}
`,
  };

  return builtInTemplates[templateName] || "";
}

/** Generate a single missing module: resolve template, render parameters, write to src/. */
export function generateModule(
  internalPath: string,
  templates: TemplateRegistry,
  fallbacks: FallbackRegistry
): GenerationResult {
  // Look up exact template first, then fall back to directory-level glob patterns
  let entry = templates[internalPath];
  let templateFile = entry?.template;

  if (!entry) {
    const fallbackTemplate = matchFallback(internalPath, fallbacks);
    if (fallbackTemplate) {
      templateFile = fallbackTemplate;
      entry = { template: fallbackTemplate };
    }
  }

  if (!templateFile) {
    return {
      success: false,
      filePath: "",
      internalPath,
      error: `No template registered for @/${internalPath}`,
    };
  }

  const templateContent = getTemplateContent(templateFile);
  if (!templateContent) {
    return {
      success: false,
      filePath: "",
      internalPath,
      error: `Template not found: ${entry.template}`,
    };
  }

  // Replace template parameter placeholders with actual values
  const rendered = renderTemplate(templateContent, entry.params || {});
  const filePath = path.join(ROOT, "src", internalPath + (internalPath.endsWith(".ts") ? "" : ".ts"));

  // Ensure directory exists before writing
  const dir = path.dirname(filePath);
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }

  // Write file
  try {
    fs.writeFileSync(filePath, rendered, "utf-8");
    return {
      success: true,
      filePath,
      internalPath,
      message: `Generated @/${internalPath}`,
    };
  } catch (e) {
    return {
      success: false,
      filePath,
      internalPath,
      error: `Failed to write file: ${e instanceof Error ? e.message : String(e)}`,
    };
  }
}

/** Generate all missing modules for a list of internal paths, logging each result. */
export function generateAll(internalPaths: string[]): GenerationResult[] {
  const { templates, fallbacks } = loadRegistry();
  const results: GenerationResult[] = [];

  for (const internalPath of internalPaths) {
    const result = generateModule(internalPath, templates, fallbacks);
    results.push(result);
    if (result.success) {
      console.log(`  ✓ ${result.message}`);
    } else {
      console.error(`  ✗ Failed @/${internalPath}: ${result.error}`);
    }
  }

  return results;
}