import express from 'express';
import { workflowDb, webhookDb, credentialsDb } from '../database/db.js';
import { refreshWorkflowSchedule, stopWorkflowSchedule, executeWorkflow } from '../services/workflowScheduler.js';
import { INTEGRATION_CATALOG } from '../../shared/integrationCatalog.js';

const router = express.Router();

// ── BYOK helpers ────────────────────────────────────────────────────
async function getUserProviderKey(userId, providerType) {
  if (!userId) return null;
  try {
    const creds = await credentialsDb.getCredentials(userId, providerType);
    const active = creds.find(c => c.is_active);
    return active?.credential_value || null;
  } catch { return null; }
}

// ── AI workflow generation prompt ───────────────────────────────────
function buildWorkflowGenerationPrompt(description, availableWebhooks, connectedIntegrations) {
  const integrationsList = INTEGRATION_CATALOG.map(i => {
    const connected = connectedIntegrations.includes(i.id);
    const actions = i.popularActions.map(a => `  - ${a.slug}: ${a.label} (params: ${a.params.join(', ')})`).join('\n');
    return `${i.name} (${i.id})${connected ? ' [CONNECTED]' : ''}:\n${actions}`;
  }).join('\n\n');

  const webhooksList = availableWebhooks.length
    ? availableWebhooks.map(w => `- ID ${w.id}: "${w.name}" (${w.method} ${w.url})`).join('\n')
    : 'No webhooks configured.';

  return `You are a workflow automation builder. Given a natural language description, generate a workflow JSON.

AVAILABLE STEP TYPES:
1. "ai-prompt" — Run an AI prompt. Config: { prompt: string }
2. "webhook" — Call an HTTP endpoint. Config: { webhookId: string, payloadTemplate?: string }
3. "delay" — Wait N seconds (max 30). Config: { seconds: number }
4. "condition" — Branch on expression. Config: { expression: string }
5. "integration" — Use a connected app via Composio. Config: { integrationId: string, toolSlug: string, arguments: { param: value } }

AVAILABLE INTEGRATIONS:
${integrationsList}

AVAILABLE WEBHOOKS:
${webhooksList}

RULES:
- Each step needs: id (unique string), type, label (human-readable), config, order (0-indexed)
- Step IDs should be like "step_1", "step_2", etc.
- For integration steps, only use integrations marked [CONNECTED] or suggest connecting them
- Use {{prev.field}} syntax in config values to reference previous step output
- If the user mentions a schedule, include schedule (cron) and schedule_enabled: true
- Keep workflows focused and practical

Respond with ONLY valid JSON in this exact format (no markdown, no explanation):
{
  "name": "Workflow Name",
  "description": "What this workflow does",
  "steps": [...],
  "schedule": null,
  "schedule_enabled": false,
  "schedule_timezone": "UTC"
}

USER REQUEST: ${description}`;
}

// ── Routes ──────────────────────────────────────────────────────────

// GET /api/workflows — list all workflows for the user
router.get('/', async (req, res) => {
  try {
    const workflows = await workflowDb.getAll(req.user.id);
    const parsed = workflows.map(w => ({
      ...w,
      steps: typeof w.steps === 'string' ? JSON.parse(w.steps) : w.steps
    }));
    res.json({ workflows: parsed });
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch workflows' });
  }
});

// POST /api/workflows — create a workflow
router.post('/', async (req, res) => {
  try {
    const { name, description, steps, schedule, schedule_enabled, schedule_timezone } = req.body;
    if (!name || !name.trim()) return res.status(400).json({ error: 'Name is required' });
    if (!Array.isArray(steps)) return res.status(400).json({ error: 'Steps must be an array' });

    const workflow = await workflowDb.create(req.user.id, {
      name: name.trim(),
      description: description?.trim() || null,
      steps,
      schedule: schedule || null,
      schedule_enabled: !!schedule_enabled,
      schedule_timezone: schedule_timezone || 'UTC'
    });

    // Sync cron scheduler
    if (workflow.id) refreshWorkflowSchedule(workflow.id, req.user.id);

    res.json({ success: true, workflow });
  } catch (error) {
    res.status(500).json({ error: 'Failed to create workflow' });
  }
});

// POST /api/workflows/generate — AI-powered workflow generation from natural language
router.post('/generate', async (req, res) => {
  try {
    const { description } = req.body;
    if (!description || !description.trim()) {
      return res.status(400).json({ error: 'Description is required' });
    }

    // Get user's API key (try Anthropic first, then OpenRouter)
    let apiKey = await getUserProviderKey(req.user.id, 'anthropic_key');
    let provider = 'anthropic';

    if (!apiKey) {
      apiKey = await getUserProviderKey(req.user.id, 'openrouter_key');
      provider = 'openrouter';
    }

    // Fall back to server key
    if (!apiKey) {
      apiKey = process.env.ANTHROPIC_API_KEY;
      provider = 'anthropic';
    }

    if (!apiKey) {
      return res.status(400).json({ error: 'No AI provider key available. Add an API key in Settings > AI Providers.' });
    }

    // Get available webhooks and connected integrations for context
    const webhooks = await webhookDb.getAll(req.user.id);
    const connectedIntegrations = []; // Will be populated if Composio is available

    const prompt = buildWorkflowGenerationPrompt(description.trim(), webhooks, connectedIntegrations);

    let generatedJson;

    if (provider === 'anthropic') {
      const response = await fetch('https://api.anthropic.com/v1/messages', {
        method: 'POST',
        headers: {
          'x-api-key': apiKey,
          'anthropic-version': '2023-06-01',
          'content-type': 'application/json',
        },
        body: JSON.stringify({
          model: 'claude-sonnet-4-20250514',
          max_tokens: 2048,
          messages: [{ role: 'user', content: prompt }],
        }),
      });

      if (!response.ok) {
        return res.status(502).json({ error: 'AI provider returned an error' });
      }

      const data = await response.json();
      const text = data.content?.[0]?.text || '';
      generatedJson = text.trim();
    } else {
      // OpenRouter
      const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${apiKey}`,
          'Content-Type': 'application/json',
          'HTTP-Referer': 'https://cli.upfyn.com',
          'X-Title': 'Upfyn-Code',
        },
        body: JSON.stringify({
          model: 'anthropic/claude-sonnet-4',
          messages: [{ role: 'user', content: prompt }],
          max_tokens: 2048,
        }),
      });

      if (!response.ok) {
        return res.status(502).json({ error: 'AI provider returned an error' });
      }

      const data = await response.json();
      generatedJson = data.choices?.[0]?.message?.content?.trim() || '';
    }

    // Parse the AI response — strip markdown fences if present
    let cleaned = generatedJson;
    if (cleaned.startsWith('```')) {
      cleaned = cleaned.replace(/^```(?:json)?\n?/, '').replace(/\n?```$/, '');
    }

    let workflow;
    try {
      workflow = JSON.parse(cleaned);
    } catch {
      return res.status(422).json({ error: 'AI generated invalid workflow format. Try rephrasing your description.' });
    }

    // Validate required fields
    if (!workflow.name || !Array.isArray(workflow.steps)) {
      return res.status(422).json({ error: 'AI generated incomplete workflow. Try being more specific.' });
    }

    // Ensure step IDs are unique
    workflow.steps = workflow.steps.map((step, i) => ({
      ...step,
      id: step.id || `step_${Date.now()}_${i}`,
      order: i,
    }));

    // Save to Turso
    const saved = await workflowDb.create(req.user.id, {
      name: workflow.name.trim(),
      description: workflow.description?.trim() || description.trim(),
      steps: workflow.steps,
      schedule: workflow.schedule || null,
      schedule_enabled: !!workflow.schedule_enabled,
      schedule_timezone: workflow.schedule_timezone || 'UTC',
    });

    if (saved.id && workflow.schedule_enabled) {
      refreshWorkflowSchedule(saved.id, req.user.id);
    }

    res.json({
      success: true,
      workflow: {
        ...saved,
        steps: workflow.steps,
      },
    });
  } catch (error) {
    res.status(500).json({ error: 'Failed to generate workflow' });
  }
});

// PUT /api/workflows/:id — update a workflow
router.put('/:id', async (req, res) => {
  try {
    const { name, description, steps, schedule, schedule_enabled, schedule_timezone } = req.body;
    if (!name || !name.trim()) return res.status(400).json({ error: 'Name is required' });

    const wfId = Number(req.params.id);
    const updated = await workflowDb.update(wfId, req.user.id, {
      name: name.trim(),
      description: description?.trim() || null,
      steps: steps || [],
      schedule: schedule || null,
      schedule_enabled: !!schedule_enabled,
      schedule_timezone: schedule_timezone || 'UTC'
    });

    if (!updated) return res.status(404).json({ error: 'Workflow not found' });

    // Sync cron scheduler
    refreshWorkflowSchedule(wfId, req.user.id);

    res.json({ success: true });
  } catch (error) {
    res.status(500).json({ error: 'Failed to update workflow' });
  }
});

// DELETE /api/workflows/:id — delete a workflow
router.delete('/:id', async (req, res) => {
  try {
    const wfId = Number(req.params.id);
    const deleted = await workflowDb.delete(wfId, req.user.id);
    if (!deleted) return res.status(404).json({ error: 'Workflow not found' });

    stopWorkflowSchedule(wfId);

    res.json({ success: true });
  } catch (error) {
    res.status(500).json({ error: 'Failed to delete workflow' });
  }
});

// POST /api/workflows/:id/run — execute a workflow (manual trigger)
router.post('/:id/run', async (req, res) => {
  try {
    const workflow = await workflowDb.getById(Number(req.params.id), req.user.id);
    if (!workflow) return res.status(404).json({ error: 'Workflow not found' });

    const steps = typeof workflow.steps === 'string' ? JSON.parse(workflow.steps) : workflow.steps;
    if (!steps.length) return res.status(400).json({ error: 'Workflow has no steps' });

    const result = await executeWorkflow({ ...workflow, steps });
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: 'Failed to run workflow' });
  }
});

// GET /api/workflows/:id/runs — list execution history for a workflow
router.get('/:id/runs', async (req, res) => {
  try {
    const runs = await workflowDb.getRuns(Number(req.params.id), req.user.id);
    const parsed = runs.map(r => ({
      ...r,
      result: typeof r.result === 'string' ? (() => { try { return JSON.parse(r.result); } catch { return r.result; } })() : r.result
    }));
    res.json({ runs: parsed });
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch workflow runs' });
  }
});

export default router;
