/**
 * VLAdjust Tool — modify existing VL projects via adjustment workflows
 *
 * This tool is the PRIMARY entry point for adjusting existing VL projects.
 * It auto-selects the right workflow based on the change request type.
 *
 * Actions:
 *   "adjust"  — Run an adjustment workflow (auto-selects or user-specified)
 *   "list"    — List available adjustment workflows
 *   "status"  — Check workflow engine status
 *
 * Sub-workflows:
 *   "add-page"         — Add a new page (section + components + route)
 *   "add-service"      — Add a new backend service domain
 *   "theme-customize"  — Customize theme tokens + cascade updates
 *   "add-feature"      — Add/modify a feature in an existing page (button, form, chart)
 *   "modify-data"      — Add/modify database fields with cascade to services + sections
 *   "batch"            — Multiple small adjustments in one pass
 *   "general"          — General incremental update (meta diff → regen affected files)
 */
import fsSync from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import os from 'os';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const VL_CODE_INSTALL_DIR = path.resolve(__dirname, '..', '..');
const VL_CODE_HOME = path.join(os.homedir(), '.vl-code');

export function createVLAdjustTool(config) {
  return {
    description: `Adjust an existing VL project — add pages, add services, customize theme, or make general changes. This is the PREFERRED way to modify existing projects.

Actions:
- "adjust": Run adjustment workflow. Requires changeRequest (description of what to change). Optional: workflow ("add-page"|"add-service"|"theme-customize"|"add-feature"|"modify-data"|"batch"|"general"), targetLang.
- "list": List available adjustment workflows.
- "status": Check engine status and current adjustment workflow progress.

The tool auto-selects the best workflow based on the change request:
- add-page: When the request involves adding a new page, screen, view, or route
- add-service: When the request involves adding a new backend service, API, or data domain
- theme-customize: When the request involves changing colors, fonts, spacing, or visual theme
- add-feature: When adding a feature to an existing page (button, form field, chart, dialog, etc.)
- modify-data: When adding/modifying database fields, tables, or data types (cascades through services and sections)
- batch: When making multiple small changes across different files in one pass
- general: For all other modifications (meta diff → regen affected files)

ALWAYS use this tool when the user asks to modify, adjust, add to, change, or update an existing VL project.`,
    parameters: {
      type: 'object',
      properties: {
        action: {
          type: 'string',
          enum: ['adjust', 'list', 'status'],
          description: 'Action to perform',
        },
        changeRequest: {
          type: 'string',
          description: 'Description of the change to make (for "adjust" action)',
        },
        workflow: {
          type: 'string',
          enum: ['add-page', 'add-service', 'theme-customize', 'add-feature', 'modify-data', 'batch', 'general'],
          description: 'Which adjustment workflow to use. If omitted, auto-selects based on changeRequest.',
        },
        targetLang: {
          type: 'string',
          description: 'Target language (default: "zh-CN")',
        },
      },
      required: ['action'],
    },
    execute: async (input) => {
      switch (input.action) {
        case 'adjust':
          return runAdjust(config, input);
        case 'list':
          return listAdjustWorkflows(config);
        case 'status':
          return JSON.stringify(buildWorkflowStatus(config), null, 2);
        default:
          return 'Unknown action. Use: adjust, list, status.';
      }
    },
  };
}

const ADJUST_WORKFLOW_MAP = {
  'add-page': '.vl-code/workflows/add-page.json',
  'add-service': '.vl-code/workflows/add-service.json',
  'theme-customize': '.vl-code/workflows/theme-customize.json',
  'add-feature': '.vl-code/workflows/feature-adjust.json',
  'modify-data': '.vl-code/workflows/data-adjust.json',
  'batch': '.vl-code/workflows/batch-adjust.json',
  'general': '.vl-code/workflows/incremental-update.json',
};

function buildWorkflowStatus(config) {
  const workflowState = typeof config._getWorkflowState === 'function'
    ? config._getWorkflowState()
    : null;
  const workDir = workflowState?.workDir || config.workDir || '';
  return {
    available: true,
    engine: 'vl-workflow-engine (JS)',
    spec: 'v3.16',
    active: !!workflowState?.active,
    workflowName: workflowState?.workflowName || null,
    nodeStatuses: workflowState?.nodeStatuses || {},
    nodeDetails: workflowState?.nodeDetails || {},
    timeline: workflowState?.timeline || [],
    startedAt: workflowState?.startedAt || null,
    finishedAt: workflowState?.finishedAt || null,
    lastError: workflowState?.lastError || null,
    workDir,
    projectName: workDir ? path.basename(workDir) : null,
    message: workflowState?.active
      ? 'An adjustment workflow is still running. Poll status until active=false before compiling or running AutoTestPipeline.'
      : 'No adjustment workflow is active.',
  };
}

/**
 * Auto-select adjustment workflow based on change request keywords
 */
function autoSelectAdjustWorkflow(changeRequest) {
  const text = changeRequest.toLowerCase();

  // Add page patterns
  const pagePatterns = [
    /add\s*(a\s+)?(?:new\s+)?page/i,
    /新增?\s*页面/,
    /添加\s*页面/,
    /加\s*一?\s*个?\s*页面/,
    /add\s*(a\s+)?(?:new\s+)?(?:screen|view|route)/i,
    /新增?\s*(?:视图|路由|屏幕|界面)/,
  ];

  // Add service patterns
  const servicePatterns = [
    /add\s*(a\s+)?(?:new\s+)?service/i,
    /新增?\s*服务/,
    /添加\s*(?:服务|接口|API)/,
    /add\s*(a\s+)?(?:new\s+)?(?:api|backend|domain)/i,
    /新增?\s*(?:数据域|后端|领域)/,
  ];

  // Theme patterns
  const themePatterns = [
    /(?:change|modify|update|customize|adjust)\s*(?:the\s+)?(?:theme|color|font|spacing)/i,
    /(?:修改|调整|更换|自定义)\s*(?:主题|颜色|字体|间距|样式)/,
    /theme\s*(?:change|update|customize)/i,
    /换\s*(?:个|一个)?\s*(?:主题|风格|配色)/,
  ];

  // Add feature to existing page patterns (must be checked BEFORE add-page)
  const featurePatterns = [
    /add\s*(a\s+)?(?:new\s+)?(?:button|form|field|chart|dialog|modal|table|tab|card|filter|sort|export|import|upload|download)/i,
    /(?:添加|增加|加)\s*(?:一个?\s*)?(?:按钮|表单|字段|图表|弹窗|对话框|表格|标签页|卡片|筛选|排序|导出|导入|上传|下载)/,
    /add\s*(a\s+)?feature/i,
    /(?:添加|增加)\s*功能/,
    /给.*(?:加|添加|增加)\s*(?:一个?)?\s*(?:按钮|功能|字段|表单|图表)/,
  ];

  // Data model patterns
  const dataPatterns = [
    /add\s*(a\s+)?(?:new\s+)?(?:field|column|table|index)/i,
    /(?:添加|增加|新增)\s*(?:字段|列|表|索引)/,
    /(?:modify|change|update)\s*(?:the\s+)?(?:database|schema|data\s*model|field\s*type)/i,
    /(?:修改|变更)\s*(?:数据库|数据模型|字段类型|表结构)/,
    /add\s*enum/i,
    /(?:添加|增加)\s*枚举/,
  ];

  // Batch patterns
  const batchPatterns = [
    /(?:batch|multiple|several|一批|批量|多个)\s*(?:change|update|fix|修改|调整|更新)/i,
    /(?:change|update|fix|修改|调整|更新)\s*(?:batch|multiple|several|一批|批量|多个)/i,
    /同时.*(?:修改|调整|更新|添加)/,
    /(?:and|以及|还有|并且).*(?:and|以及|还有|并且)/,
  ];

  for (const p of featurePatterns) {
    if (p.test(changeRequest)) return 'add-feature';
  }
  for (const p of pagePatterns) {
    if (p.test(changeRequest)) return 'add-page';
  }
  for (const p of servicePatterns) {
    if (p.test(changeRequest)) return 'add-service';
  }
  for (const p of dataPatterns) {
    if (p.test(changeRequest)) return 'modify-data';
  }
  for (const p of themePatterns) {
    if (p.test(changeRequest)) return 'theme-customize';
  }
  for (const p of batchPatterns) {
    if (p.test(changeRequest)) return 'batch';
  }

  return 'general';
}

/**
 * Read current ProjectMeta from disk
 */
function readCurrentMeta(workDir) {
  const metaPath = path.join(workDir, '.vl-code', 'ProjectMeta.json');
  if (!fsSync.existsSync(metaPath)) return null;
  try {
    return JSON.parse(fsSync.readFileSync(metaPath, 'utf-8'));
  } catch {
    return null;
  }
}

async function runAdjust(config, input) {
  const { changeRequest, workflow, targetLang = 'zh-CN' } = input;

  if (!changeRequest) {
    return 'Error: changeRequest is required. Describe what you want to change.';
  }

  // Auto-read ProjectMeta (all adjustment workflows need it)
  const currentMeta = readCurrentMeta(config.workDir);
  if (!currentMeta) {
    return 'Error: No ProjectMeta.json found in .vl-code/. This tool requires an existing project. Use VLGenerate to create a new project first.';
  }

  // Select workflow: explicit > auto-select
  const selectedWorkflow = workflow || autoSelectAdjustWorkflow(changeRequest);
  const workflowPath = ADJUST_WORKFLOW_MAP[selectedWorkflow];

  if (!workflowPath) {
    return `Error: Unknown workflow "${selectedWorkflow}". Available: ${Object.keys(ADJUST_WORKFLOW_MAP).join(', ')}.`;
  }

  // Search for workflow file
  const searchDirs = [
    path.join(config.workDir, '.vl-code', 'workflows'),
    path.join(VL_CODE_INSTALL_DIR, '.vl-code', 'workflows'),
    path.join(VL_CODE_HOME, 'workflows'),
  ];

  let wfJson = null;
  const wfFile = path.basename(workflowPath);

  for (const dir of searchDirs) {
    const fp = path.join(dir, wfFile);
    if (fsSync.existsSync(fp)) {
      try {
        wfJson = JSON.parse(fsSync.readFileSync(fp, 'utf-8'));
        break;
      } catch {}
    }
  }

  if (!wfJson) {
    return `Error: Workflow file "${wfFile}" not found in any of:\n${searchDirs.map(d => '  - ' + d).join('\n')}`;
  }

  // Build params — each sub-workflow expects different param names
  const params = { targetLang, currentMeta };

  switch (selectedWorkflow) {
    case 'add-page':
      params.pageDescription = changeRequest;
      break;
    case 'add-service':
      params.serviceDescription = changeRequest;
      break;
    case 'theme-customize':
      params.themeRequest = changeRequest;
      break;
    case 'add-feature':
      params.featureRequest = changeRequest;
      break;
    case 'modify-data':
      params.dataRequest = changeRequest;
      break;
    case 'batch':
      params.batchRequest = changeRequest;
      break;
    case 'general':
      params.changeRequest = changeRequest;
      break;
  }

  const broadcast = config._broadcast || (() => {});
  const recordWorkflowEvent = config._recordWorkflowEvent || (() => {});

  try {
    const { WorkflowExecutor } = await import('../vl/workflow-executor.js');
    const executor = new WorkflowExecutor({
      apiKey: config.apiKey,
      model: config.model,
      llmProvider: config.llmProvider,
      workDir: config.workDir,
      cookie: config.cookie,
      toolRegistry: config.toolRegistry || config._toolRegistry || null,
    });

    if (config._setActiveExecutor) config._setActiveExecutor(executor);
    if (config._onWorkflowStart) config._onWorkflowStart(selectedWorkflow, { stepCount: wfJson.steps?.length || 0 });
    broadcast({
      type: 'workflow_execution_start',
      workflowName: selectedWorkflow,
      workflow: wfJson,
      stepCount: wfJson.steps?.length || 0,
    });
    broadcast({ type: 'wf_start', workflowName: selectedWorkflow, stepCount: wfJson.steps?.length || 0, model: config.model || 'unknown' });
    recordWorkflowEvent({ type: 'wf_start', workflowName: selectedWorkflow, stepCount: wfJson.steps?.length || 0, model: config.model || 'unknown' });

    executor.execute(wfJson, params, {
      onNodeStart: (info) => {
        if (config._onWorkflowNodeStatus) config._onWorkflowNodeStatus(info.nodeId, 'running', {
          title: info.title,
          type: info.type,
          input: info.input,
          resolvedInputs: info.resolvedInputs,
        });
        broadcast({ type: 'workflow_node_update', nodeId: info.nodeId, status: 'running', title: info.title || info.nodeId });
        broadcast({ type: 'wf_node_start', nodeId: info.nodeId, title: info.title, nodeType: info.type, input: info.input, resolvedInputs: info.resolvedInputs });
        recordWorkflowEvent({ type: 'wf_node_start', nodeId: info.nodeId, status: 'running', title: info.title, nodeType: info.type, input: info.input, resolvedInputs: info.resolvedInputs });
      },
      onNodeDone: (info) => {
        if (config._onWorkflowNodeStatus) config._onWorkflowNodeStatus(info.nodeId, 'done', {
          title: info.title,
          output: info.output,
          outputs: info.outputs,
          selected: info.selected,
          duration_ms: info.duration_ms,
        });
        broadcast({ type: 'workflow_node_update', nodeId: info.nodeId, status: 'done', title: info.title || info.nodeId });
        broadcast({ type: 'wf_node_done', nodeId: info.nodeId, title: info.title, duration_ms: info.duration_ms, output: info.output, outputs: info.outputs, selected: info.selected });
        recordWorkflowEvent({ type: 'wf_node_done', nodeId: info.nodeId, status: 'done', title: info.title, duration_ms: info.duration_ms, output: info.output, outputs: info.outputs, selected: info.selected });
      },
      onNodeError: (info) => {
        if (config._onWorkflowNodeStatus) config._onWorkflowNodeStatus(info.nodeId, 'error', {
          title: info.title,
          type: info.type,
          error: info.error,
          detail: info.detail,
          duration_ms: info.duration_ms,
        });
        broadcast({ type: 'workflow_node_update', nodeId: info.nodeId, status: 'error', error: info.error });
        broadcast({ type: 'wf_node_error', nodeId: info.nodeId, title: info.title, error: info.error, detail: info.detail, duration_ms: info.duration_ms });
        recordWorkflowEvent({ type: 'wf_node_error', nodeId: info.nodeId, status: 'error', title: info.title, nodeType: info.type, error: info.error, detail: info.detail, duration_ms: info.duration_ms });
      },
      onNodeSkipped: (info) => {
        if (config._onWorkflowNodeStatus) config._onWorkflowNodeStatus(info.nodeId, 'skipped', { reason: info.reason || 'condition false' });
        broadcast({ type: 'workflow_node_update', nodeId: info.nodeId, status: 'skipped' });
        broadcast({ type: 'wf_node_skipped', nodeId: info.nodeId });
        recordWorkflowEvent({ type: 'wf_node_skipped', nodeId: info.nodeId, status: 'skipped', reason: info.reason || 'condition false' });
      },
      onPause: (info) => {
        if (config._onWorkflowNodeStatus) config._onWorkflowNodeStatus(info.nodeId, 'paused', info);
        broadcast({ type: 'workflow_node_update', nodeId: info.nodeId, status: 'paused', title: info.title || info.nodeId });
        broadcast({ type: 'wf_pause', ...info });
        recordWorkflowEvent({ type: 'wf_pause', nodeId: info.nodeId, status: 'paused', title: info.title, reason: info.reason });
      },
      onResumed: (info) => {
        if (config._onWorkflowNodeStatus) config._onWorkflowNodeStatus(info.nodeId, 'running', info);
        broadcast({ type: 'workflow_node_update', nodeId: info.nodeId, status: 'running', title: info.title || info.nodeId });
        broadcast({ type: 'wf_resumed', ...info });
        recordWorkflowEvent({ type: 'wf_resumed', nodeId: info.nodeId, status: 'running' });
      },
      onVarsChanged: (nodeId, vars) => {
        broadcast({ type: 'wf_vars', nodeId, vars });
        recordWorkflowEvent({ type: 'wf_vars', nodeId, output: vars });
      },
      onLLMThinking: (info) => {
        broadcast({ type: 'wf_llm_thinking', ...info });
        recordWorkflowEvent({ type: 'wf_llm_thinking', nodeId: info.stepId, text: info.delta });
      },
      onLLMToolUse: (info) => {
        broadcast({ type: 'wf_llm_tool_use', ...info });
        recordWorkflowEvent({ type: 'wf_llm_tool_use', nodeId: info.stepId, name: info.name, input: info.input, tool_use_id: info.tool_use_id });
      },
      onLLMToolResult: (info) => {
        broadcast({ type: 'wf_llm_tool_result', ...info });
        recordWorkflowEvent({ type: 'wf_llm_tool_result', nodeId: info.stepId, tool_use_id: info.tool_use_id, output: info.content, error: info.is_error ? info.content : undefined });
      },
      onLLMDone: (info) => {
        broadcast({ type: 'wf_llm_done', ...info });
        recordWorkflowEvent({ type: 'wf_llm_done', nodeId: info.stepId, model: info.model, usage: info.usage, duration_ms: info.latency_ms });
      },
      onLLMError: (info) => {
        broadcast({ type: 'wf_llm_error', ...info });
        recordWorkflowEvent({ type: 'wf_llm_error', nodeId: info.stepId, error: info.error, detail: info.code, duration_ms: info.latency_ms });
      },
      onToolStart: (info) => {
        broadcast({ type: 'wf_tool_start', ...info });
        recordWorkflowEvent({ type: 'wf_tool_start', nodeId: info.stepId, name: info.name, input: info.input });
      },
      onToolDone: (info) => {
        broadcast({ type: 'wf_tool_done', ...info });
        recordWorkflowEvent({ type: 'wf_tool_done', nodeId: info.stepId, name: info.name, output: info.output });
      },
      onToolError: (info) => {
        broadcast({ type: 'wf_tool_error', ...info });
        recordWorkflowEvent({ type: 'wf_tool_error', nodeId: info.stepId, name: info.name, error: info.error, output: info.output });
      },
      onToolMessage: (info) => {
        broadcast({ type: 'wf_tool_message', ...info });
        recordWorkflowEvent({ type: 'wf_tool_message', nodeId: info.stepId, name: info.name, level: info.level, message: info.message, output: info.data });
      },
      onFileStart: (fp) => {
        broadcast({ type: 'wf_file_start', path: fp });
        recordWorkflowEvent({ type: 'wf_file_start', path: fp });
      },
      onVarChanged: (info) => {
        broadcast({ type: 'wf_var_changed', ...info });
        recordWorkflowEvent({ type: 'wf_var_changed', nodeId: info.stepId, title: info.name, output: info.newValue });
      },
      onFileWritten: (fp) => {
        broadcast({ type: 'file_changed', path: fp });
        broadcast({ type: 'wf_file_done', path: fp });
        recordWorkflowEvent({ type: 'wf_file_done', path: fp });
      },
      onFileChanged: (fp, sizeBytes) => {
        broadcast({ type: 'file_changed', path: fp, size_bytes: sizeBytes });
      },
      onToken: (token) => {
        broadcast({ type: 'wf_token', token });
      },
      onText: (text) => {
        broadcast({ type: 'wf_text', text });
        recordWorkflowEvent({ type: 'wf_text', text });
      },
      onCheckpoint: (cp) => {
        broadcast({ type: 'wf_checkpoint', runID: cp.workflowID, stepID: cp.currentStepID, completedSteps: cp.completedSteps, checkpoint: cp });
        recordWorkflowEvent({ type: 'wf_checkpoint', stepID: cp.currentStepID, completedSteps: cp.completedSteps, runID: cp.workflowID });
      },
      onDone: (info) => {
        if (config._onWorkflowDone) config._onWorkflowDone();
        broadcast({ type: 'workflow_done', workflowName: selectedWorkflow, ...info });
        broadcast({ type: 'wf_done', workflowName: selectedWorkflow, ...info });
        broadcast({ type: 'project_reloaded' });
        recordWorkflowEvent({ type: 'wf_done', workflowName: selectedWorkflow, output: info });
      },
      onError: (msg) => {
        if (config._onWorkflowError) config._onWorkflowError(selectedWorkflow, msg);
        broadcast({ type: 'workflow_error', workflowName: selectedWorkflow, error: msg });
        broadcast({ type: 'wf_error', workflowName: selectedWorkflow, error: msg });
        recordWorkflowEvent({ type: 'wf_error', workflowName: selectedWorkflow, error: msg });
      },
    }).catch(err => {
      if (config._onWorkflowError) config._onWorkflowError(selectedWorkflow, err.message);
      broadcast({ type: 'workflow_error', workflowName: selectedWorkflow, error: err.message });
      broadcast({ type: 'wf_error', workflowName: selectedWorkflow, error: err.message });
      recordWorkflowEvent({ type: 'wf_error', workflowName: selectedWorkflow, error: err.message });
    });

    return JSON.stringify({
      status: 'started',
      workflow: selectedWorkflow,
      workflowName: wfJson.name,
      stepCount: wfJson.steps?.length || 0,
      message: `Adjustment workflow "${wfJson.name}" started. Watch the Flow tab for real-time progress.`,
    }, null, 2);
  } catch (err) {
    return `Workflow execution failed: ${err.message}`;
  }
}

async function listAdjustWorkflows(config) {
  const workflows = [];
  const searchDirs = [
    path.join(config.workDir, '.vl-code', 'workflows'),
    path.join(VL_CODE_INSTALL_DIR, '.vl-code', 'workflows'),
    path.join(VL_CODE_HOME, 'workflows'),
  ];

  for (const [key, relPath] of Object.entries(ADJUST_WORKFLOW_MAP)) {
    const wfFile = path.basename(relPath);
    let info = { id: key, path: relPath, available: false };

    for (const dir of searchDirs) {
      const fp = path.join(dir, wfFile);
      if (fsSync.existsSync(fp)) {
        try {
          const wf = JSON.parse(fsSync.readFileSync(fp, 'utf-8'));
          info.available = true;
          info.name = wf.name;
          info.description = wf.description || '';
          info.version = wf.version;
          info.stepCount = wf.steps?.length || 0;
          info.params = wf.registry?.params || [];
          break;
        } catch {}
      }
    }

    workflows.push(info);
  }

  return JSON.stringify(workflows, null, 2);
}
