// backend/src/routes/niche.js
// Niche profiles + Topic Proposal approval flow

import { Router } from 'express';
import { z } from 'zod';
import { query, transaction } from '../utils/db.js';
import { requireAuth, requireActive } from '../middleware/auth.js';
import { getProviderForUser } from '../services/ai-provider.js';
import { IntelAgent } from '../jobs/agents.js';
import { logger } from '../utils/logger.js';

const router = Router();

// ─── NICHE PROFILES ───────────────────────────────────────────────────────

const NicheSchema = z.object({
  name:            z.string().min(2).max(100),
  industry:        z.string().min(2).max(100),
  subNiche:        z.string().min(5).max(200),
  contentAngle:    z.string().min(5).max(300),
  uniqueValue:     z.string().max(300).optional(),
  audienceAge:     z.string().max(50).optional(),
  audienceGender:  z.string().max(50).optional(),
  audienceLevel:   z.enum(['beginner', 'intermediate', 'expert', 'mixed']).optional(),
  audienceGoals:   z.array(z.string()).max(8).optional(),
  audiencePains:   z.array(z.string()).max(8).optional(),
  platforms:       z.array(z.enum(['youtube', 'instagram', 'x', 'tiktok', 'linkedin', 'blog'])).optional(),
  contentFormats:  z.array(z.string()).optional(),
  topicsToAvoid:   z.array(z.string()).optional(),
  seedKeywords:    z.array(z.string()).max(20).optional(),
  trendingSources: z.array(z.string()).optional(),
  competitorUrls:  z.array(z.string()).optional(),
});

// GET /api/niche — list all niche profiles for user
router.get('/', requireAuth, async (req, res) => {
  const { rows } = await query(
    'SELECT * FROM niche_profiles WHERE user_id = $1 ORDER BY is_active DESC, created_at DESC',
    [req.user.id]
  );
  res.json(rows);
});

// GET /api/niche/active — get active niche
router.get('/active', requireAuth, async (req, res) => {
  const { rows } = await query(
    'SELECT * FROM niche_profiles WHERE user_id = $1 AND is_active = true LIMIT 1',
    [req.user.id]
  );
  res.json(rows[0] || null);
});

// POST /api/niche — create niche profile
router.post('/', requireAuth, async (req, res) => {
  try {
    const data = NicheSchema.parse(req.body);
    const { rows } = await query(
      `INSERT INTO niche_profiles
        (user_id, name, industry, sub_niche, content_angle, unique_value,
         audience_age, audience_gender, audience_level, audience_goals, audience_pains,
         platforms, content_formats, topics_to_avoid, seed_keywords, trending_sources, competitor_urls)
       VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)
       RETURNING *`,
      [req.user.id, data.name, data.industry, data.subNiche, data.contentAngle,
       data.uniqueValue, data.audienceAge, data.audienceGender, data.audienceLevel,
       data.audienceGoals || [], data.audiencePains || [],
       data.platforms || [], data.contentFormats || [],
       data.topicsToAvoid || [], data.seedKeywords || [],
       data.trendingSources || [], data.competitorUrls || []]
    );
    res.status(201).json(rows[0]);
  } catch (err) {
    if (err instanceof z.ZodError) return res.status(400).json({ error: 'validation', issues: err.issues });
    res.status(500).json({ error: err.message });
  }
});

// PUT /api/niche/:id — update niche
router.put('/:id', requireAuth, async (req, res) => {
  try {
    const data = NicheSchema.parse(req.body);
    const { rows } = await query(
      `UPDATE niche_profiles SET
        name=$2, industry=$3, sub_niche=$4, content_angle=$5, unique_value=$6,
        audience_age=$7, audience_gender=$8, audience_level=$9,
        audience_goals=$10, audience_pains=$11, platforms=$12, content_formats=$13,
        topics_to_avoid=$14, seed_keywords=$15, trending_sources=$16, competitor_urls=$17,
        updated_at=NOW()
       WHERE id=$1 AND user_id=$18 RETURNING *`,
      [req.params.id, data.name, data.industry, data.subNiche, data.contentAngle,
       data.uniqueValue, data.audienceAge, data.audienceGender, data.audienceLevel,
       data.audienceGoals || [], data.audiencePains || [],
       data.platforms || [], data.contentFormats || [],
       data.topicsToAvoid || [], data.seedKeywords || [],
       data.trendingSources || [], data.competitorUrls || [], req.user.id]
    );
    if (!rows[0]) return res.status(404).json({ error: 'Not found' });
    res.json(rows[0]);
  } catch (err) {
    if (err instanceof z.ZodError) return res.status(400).json({ error: 'validation', issues: err.issues });
    res.status(500).json({ error: err.message });
  }
});

// POST /api/niche/:id/activate — set as active niche
router.post('/:id/activate', requireAuth, async (req, res) => {
  await transaction(async (client) => {
    await client.query('UPDATE niche_profiles SET is_active = false WHERE user_id = $1', [req.user.id]);
    await client.query('UPDATE niche_profiles SET is_active = true WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]);
  });
  res.json({ success: true });
});

// DELETE /api/niche/:id
router.delete('/:id', requireAuth, async (req, res) => {
  await query('DELETE FROM niche_profiles WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]);
  res.json({ success: true });
});

// ─── TOPIC PROPOSALS ──────────────────────────────────────────────────────

// POST /api/niche/:id/propose-topics — AI generates topic proposals
router.post('/:nicheId/propose-topics', requireAuth, requireActive, async (req, res) => {
  const { nicheId } = req.params;
  const { count = 7 } = req.body;

  try {
    // Get niche
    const { rows: nicheRows } = await query(
      'SELECT * FROM niche_profiles WHERE id = $1 AND user_id = $2',
      [nicheId, req.user.id]
    );
    if (!nicheRows[0]) return res.status(404).json({ error: 'Niche not found' });
    const niche = nicheRows[0];

    // Get user plan
    const { rows: userRows } = await query(
      'SELECT u.*, p.byok FROM users u LEFT JOIN plans p ON u.plan_id = p.id WHERE u.id = $1',
      [req.user.id]
    );
    const user = userRows[0];

    // Get AI provider
    const ai = await getProviderForUser(req.user.id, { byok: user.byok });

    // Build rich context from niche profile
    const nicheContext = buildNicheContext(niche);

    const system = `You are an expert YouTube content strategist. You generate highly specific, timely video topic proposals based on a detailed niche profile. Each topic must be actionable and tailored precisely to the creator's audience and angle.`;

    const prompt = `Generate ${count} YouTube video topic proposals for this niche profile:

${nicheContext}

For EACH topic, provide a structured proposal in this EXACT format (use --- as separator):

TOPIC_START
TITLE: [SEO-optimized, clickable title — be specific, not generic]
ANGLE: [What unique perspective makes this different from existing videos]
HOOK: [First 2 sentences to open the video — must grab attention immediately]
WHY_NOW: [Why this topic is relevant/timely right now]
SEARCH_INTENT: [informational | commercial | navigational]
DIFFICULTY: [easy | medium | hard — to rank on YouTube]
AUDIENCE_FIT: [1-2 sentences on why this specifically fits the described audience]
TOPIC_END

Generate all ${count} topics now. Be specific — avoid generic titles like "How to lose weight". Instead: "Why 80% of Women Over 35 Can't Lose Belly Fat (And What Actually Works)".`;

    const raw = await ai.complete(system, prompt, 3000);

    // Parse structured proposals
    const proposals = parseTopicProposals(raw);

    if (proposals.length === 0) {
      return res.status(500).json({ error: 'Failed to parse topic proposals', raw });
    }

    // Save to DB
    const saved = [];
    for (const p of proposals) {
      const { rows } = await query(
        `INSERT INTO topic_proposals
          (user_id, niche_id, proposed_title, proposed_angle, proposed_hook,
           search_intent, difficulty, why_now)
         VALUES ($1,$2,$3,$4,$5,$6,$7,$8)
         RETURNING *`,
        [req.user.id, nicheId, p.title, p.angle, p.hook, p.searchIntent, p.difficulty, p.whyNow]
      );
      saved.push(rows[0]);
    }

    logger.info(`Generated ${saved.length} topic proposals for user ${req.user.id}`);
    res.json({ proposals: saved, nicheId, count: saved.length });

  } catch (err) {
    logger.error('Topic proposal error', err);
    res.status(500).json({ error: err.message });
  }
});

// GET /api/niche/proposals — get pending proposals for user
router.get('/proposals', requireAuth, async (req, res) => {
  const { status = 'pending', nicheId } = req.query;
  let where = 'WHERE tp.user_id = $1';
  const params = [req.user.id];
  let idx = 2;

  if (status) { where += ` AND tp.status = $${idx++}`; params.push(status); }
  if (nicheId) { where += ` AND tp.niche_id = $${idx++}`; params.push(nicheId); }

  const { rows } = await query(
    `SELECT tp.*, np.name as niche_name, np.sub_niche
     FROM topic_proposals tp
     LEFT JOIN niche_profiles np ON tp.niche_id = np.id
     ${where}
     ORDER BY tp.created_at DESC
     LIMIT 50`,
    params
  );
  res.json(rows);
});

// PATCH /api/niche/proposals/:id — approve / reject / modify
// PATCH /api/niche/proposals/bulk — bulk approve/reject (MUST be before /:id)
router.patch('/proposals/bulk', requireAuth, async (req, res) => {
  const { ids, status } = req.body;
  if (!Array.isArray(ids) || ids.length === 0) return res.status(400).json({ error: 'ids required' });
  if (!['approved', 'rejected'].includes(status)) return res.status(400).json({ error: 'Invalid status' });

  await query(
    `UPDATE topic_proposals
     SET status = $1, approved_at = CASE WHEN $1 = 'approved' THEN NOW() ELSE NULL END
     WHERE id = ANY($2) AND user_id = $3`,
    [status, ids, req.user.id]
  );
  res.json({ success: true, count: ids.length });
});

router.patch('/proposals/:id', requireAuth, async (req, res) => {
  const { status, finalTitle, clientNotes } = req.body;

  if (!['approved', 'rejected', 'modified'].includes(status)) {
    return res.status(400).json({ error: 'Invalid status' });
  }

  const { rows } = await query(
    `UPDATE topic_proposals
     SET status = $1,
         final_title = COALESCE($2, proposed_title),
         client_notes = $3,
         approved_at = CASE WHEN $1 IN ('approved','modified') THEN NOW() ELSE NULL END
     WHERE id = $4 AND user_id = $5
     RETURNING *`,
    [status, finalTitle, clientNotes, req.params.id, req.user.id]
  );

  if (!rows[0]) return res.status(404).json({ error: 'Proposal not found' });
  res.json(rows[0]);
});

// POST /api/niche/run-with-topics — trigger pipeline with approved topics
router.post('/run-with-topics', requireAuth, requireActive, async (req, res) => {
  const { nicheId, topicIds } = req.body;

  if (!nicheId) return res.status(400).json({ error: 'nicheId required' });
  if (!Array.isArray(topicIds) || topicIds.length === 0) {
    return res.status(400).json({ error: 'Select at least 1 approved topic' });
  }

  // Verify all topics belong to user and are approved
  const { rows: topicRows } = await query(
    `SELECT id, final_title, proposed_title FROM topic_proposals
     WHERE id = ANY($1) AND user_id = $2 AND status IN ('approved','modified')`,
    [topicIds, req.user.id]
  );

  if (topicRows.length === 0) {
    return res.status(400).json({ error: 'No valid approved topics found' });
  }

  // Enforce same usage limits as /pipeline/run (running check + daily limit)
  const check = await checkPipelineAllowed(req.user.id);
  if (!check.allowed) return res.status(check.status).json(check.payload);

  // Import and enqueue
  const { enqueuePipeline } = await import('../jobs/pipeline-worker.js');
  const jobId = await enqueuePipeline(req.user.id, 'manual', {
    nicheId,
    approvedTopics: topicRows.map(t => ({ id: t.id, title: t.final_title || t.proposed_title })),
  });

  res.json({ success: true, jobId, topicsCount: topicRows.length, runsRemaining: check.remaining });
});

// ─── HELPERS ──────────────────────────────────────────────────────────────

function buildNicheContext(niche) {
  return `NICHE PROFILE:
Name: ${niche.name}
Industry: ${niche.industry}
Sub-niche: ${niche.sub_niche}
Content angle: ${niche.content_angle}
Unique value/story: ${niche.unique_value || 'Not specified'}

AUDIENCE:
Age range: ${niche.audience_age || 'Not specified'}
Gender: ${niche.audience_gender || 'Mixed'}
Knowledge level: ${niche.audience_level || 'Mixed'}
Goals: ${(niche.audience_goals || []).join(', ') || 'Not specified'}
Pain points: ${(niche.audience_pains || []).join(', ') || 'Not specified'}

CONTENT:
Platforms: ${(niche.platforms || []).join(', ') || 'YouTube'}
Formats: ${(niche.content_formats || []).join(', ') || 'Long-form video'}
Topics to AVOID: ${(niche.topics_to_avoid || []).join(', ') || 'None'}
Seed keywords: ${(niche.seed_keywords || []).join(', ') || 'None'}`;
}

function parseTopicProposals(raw) {
  const proposals = [];
  const blocks = raw.split('TOPIC_START').slice(1);

  for (const block of blocks) {
    const end = block.indexOf('TOPIC_END');
    const content = end > -1 ? block.substring(0, end) : block;

    const get = (key) => {
      const match = content.match(new RegExp(`${key}:\\s*([^\\n]+)`));
      return match ? match[1].trim() : '';
    };

    const title = get('TITLE');
    if (!title) continue;

    proposals.push({
      title,
      angle:        get('ANGLE'),
      hook:         get('HOOK'),
      whyNow:       get('WHY_NOW'),
      searchIntent: get('SEARCH_INTENT').toLowerCase().split(' ')[0] || 'informational',
      difficulty:   get('DIFFICULTY').toLowerCase().split(' ')[0] || 'medium',
      audienceFit:  get('AUDIENCE_FIT'),
    });
  }

  // Fallback: numbered list parsing if structured parsing fails
  if (proposals.length === 0) {
    const lines = raw.split('\n');
    for (const line of lines) {
      const match = line.match(/^(?:TITLE:|[\d]+\.\s+)(.{20,})/);
      if (match) proposals.push({ title: match[1].trim(), angle: '', hook: '', whyNow: '', searchIntent: 'informational', difficulty: 'medium' });
    }
  }

  return proposals;
}

export default router;
