import type {
  AstOperation,
  GoaArchitectInput,
  GoaExecutionPayload,
  GoaInstruction,
  WorkspaceType,
} from '@/types/goa-orchestrator';
import { extractVariablesFromPrompt, resolveTemplateIdFromPrompt } from '@/lib/template-catalog';

const BROWNFIELD_SIGNALS =
  /\b(fix|repair|bug|error|broken|legacy|refactor|hook|middleware|existing|my app|express|next\.js|vite)\b/i;
const GREENFIELD_SIGNALS =
  /\b(new|create|build|add|landing|template|from scratch|greenfield|scaffold|generate)\b/i;

export function classifyWorkspaceType(
  prompt: string,
  isExistingProject: boolean,
): WorkspaceType {
  if (BROWNFIELD_SIGNALS.test(prompt)) return 'BROWNFIELD';
  if (GREENFIELD_SIGNALS.test(prompt) && !isExistingProject) return 'GREENFIELD';
  if (isExistingProject) return 'BROWNFIELD';
  return 'GREENFIELD';
}

function detectFrameworkHint(prompt: string, metadata?: Record<string, unknown> | null): string {
  const fromMeta = metadata?.framework;
  if (typeof fromMeta === 'string' && fromMeta) return fromMeta;
  const lower = prompt.toLowerCase();
  if (lower.includes('next.js') || lower.includes('nextjs')) return 'Next.js';
  if (lower.includes('express')) return 'Express';
  if (lower.includes('vite')) return 'Vite';
  if (lower.includes('react')) return 'React';
  return 'Unknown';
}

function extractTargetFiles(prompt: string, metadata?: Record<string, unknown> | null): string[] {
  const pathMatch = prompt.match(/(?:[\./][\w./-]+\.(?:tsx?|jsx?|py|go|rs))/g);
  if (pathMatch?.length) return [...new Set(pathMatch)].slice(0, 8);
  const files = metadata?.target_files ?? metadata?.files_matched;
  if (Array.isArray(files)) return files.map(String).slice(0, 8);
  return [];
}

function extractAnchor(prompt: string): string | undefined {
  const hook = prompt.match(/\b(use[A-Z]\w+|handle[A-Z]\w+|auth\w*)\b/);
  if (hook) return hook[1];
  const path = prompt.match(/[\w./-]+\.(tsx?|jsx?)/);
  return path?.[0];
}

/** Layer 1 — deterministic architect: emits strict JSON execution payload (no prose). */
export function buildGoaExecutionPayload(input: GoaArchitectInput): GoaExecutionPayload {
  const workspaceType = classifyWorkspaceType(input.userPrompt, input.isExistingProject);
  const framework = detectFrameworkHint(input.userPrompt, input.astMetadata ?? undefined);
  const targetFiles = extractTargetFiles(input.userPrompt, input.astMetadata ?? undefined);
  const anchor = extractAnchor(input.userPrompt);
  const variables = extractVariablesFromPrompt(input.userPrompt);

  const instructions: GoaInstruction[] = [];

  if (workspaceType === 'GREENFIELD') {
    const templateId =
      input.templateMatch?.id ||
      resolveTemplateIdFromPrompt(input.userPrompt) ||
      'hello-world-minimal';
    instructions.push({
      sequence: 1,
      engine: 'CLI_TEMPLATE',
      command: 'EXECUTE_TEMPLATE_INJECTION',
      payload: {
        template_id: templateId,
        target_dir: './',
        variables: {
          TITLE: variables.COMPANY_NAME || 'Vigthoria Project',
          COMPANY_NAME: variables.COMPANY_NAME || 'Vigthoria',
          ...variables,
        },
        code_payload: input.userPrompt.slice(0, 500),
      },
    });
    instructions.push({
      sequence: 2,
      engine: 'STABILIZATION',
      command: 'RUN_STABILIZATION_CHECK',
      payload: { file_path: 'package.json' },
    });
  } else {
    instructions.push({
      sequence: 1,
      engine: 'AST_TRANSFORMER',
      command: 'EXECUTE_AST_MUTATION',
      payload: {
        query: anchor || input.userPrompt.slice(0, 200),
        file_path: targetFiles[0] || '',
        operation: inferAstOperation(input.userPrompt),
        target_node: anchor || 'entry_export',
        code_payload: input.userPrompt.slice(0, 800),
      },
    });
    if (targetFiles.length > 1) {
      instructions.push({
        sequence: 2,
        engine: 'AST_TRANSFORMER',
        command: 'EXECUTE_AST_MUTATION',
        payload: {
          file_path: targetFiles[1],
          operation: 'ADD_IMPORT',
          target_node: 'module_imports',
          code_payload: '',
        },
      });
    }
    instructions.push({
      sequence: instructions.length + 1,
      engine: 'STABILIZATION',
      command: 'RUN_STABILIZATION_CHECK',
      payload: { file_path: targetFiles[0] || 'package.json' },
    });
  }

  return {
    workspace_type: workspaceType,
    analysis: {
      detected_framework: framework,
      target_files: targetFiles,
      anchor_hint: anchor,
      template_match: input.templateMatch?.id,
      metadata_summary: summarizeAstMetadata(input.astMetadata ?? undefined),
      ...(input.astMetadata?.dependency_graph && typeof input.astMetadata.dependency_graph === 'object'
        ? { dependency_graph: input.astMetadata.dependency_graph as Record<string, unknown> }
        : {}),
    },
    instructions,
  };
}

function summarizeAstMetadata(metadata?: Record<string, unknown> | null): string | undefined {
  if (!metadata) return undefined;
  const parts: string[] = [];
  if (typeof metadata.symbols_extracted === 'number') {
    parts.push(`AST symbols: ${metadata.symbols_extracted}`);
  }
  if (metadata.dependency_graph && typeof metadata.dependency_graph === 'object') {
    const g = metadata.dependency_graph as Record<string, unknown>;
    if (typeof g.file_count === 'number') parts.push(`deps: ${g.file_count} files`);
    else parts.push('dependency graph attached');
  }
  if (typeof metadata.framework === 'string') parts.push(`framework: ${metadata.framework}`);
  return parts.length ? parts.join(' · ') : undefined;
}

function inferAstOperation(prompt: string): AstOperation {
  const lower = prompt.toLowerCase();
  if (lower.includes('import')) return 'ADD_IMPORT';
  if (lower.includes('wrap') || lower.includes('hoc') || lower.includes('provider')) return 'INJECT_WRAPPER';
  if (lower.includes('config') || lower.includes('package.json') || lower.includes('tailwind')) {
    return 'APPEND_PROPERTY';
  }
  if (lower.includes('before') || lower.includes('insert')) return 'INSERT_BEFORE';
  return 'REPLACE_BODY';
}

export function parseGoaPayloadJson(raw: string): GoaExecutionPayload | null {
  try {
    const trimmed = raw.trim().replace(/^```json\s*/i, '').replace(/```\s*$/, '');
    const parsed = JSON.parse(trimmed) as GoaExecutionPayload;
    if (!parsed.workspace_type || !Array.isArray(parsed.instructions)) return null;
    return parsed;
  } catch {
    return null;
  }
}

export function formatGoaPayload(payload: GoaExecutionPayload): string {
  return JSON.stringify(payload, null, 2);
}
