/**
 * Book AI Context Routes
 *
 * API endpoints for Book AI generation.
 * POST /auto-fill — generate a complete book concept from company context
 * POST /regenerate — regenerate a book concept
 */

import express, { Request, Response } from 'express';
import { body, validationResult } from 'express-validator';
import { authenticate } from '../middleware/auth';
import { requirePermission } from '../middleware/permissions';
import { BookPipeline } from '../services/aiContext/bookPipeline';
import { BookPipelineInputs, buildTranslateContentPrompt } from '../services/aiContext/bookPrompts';
import { aiContextService, computeBookAutoFillMapping } from '../services/aiContext/aiContextService';
import { getModels } from '../models';
import { createJob, updateJobProgress, completeJob, failJob, getJob } from '../services/aiContext/aiJobManager';
import { generateWithAI } from '../utils/aiProvider';

// Helper: call AI and strip markdown fences
async function generateBookAI(prompt: string, systemPrompt: string, maxTokens: number = 40000, userId?: string): Promise<string> {
  const result = await generateWithAI(prompt, systemPrompt, maxTokens, undefined, undefined, undefined, undefined, userId);
  let cleaned = result.content.trim();
  if (cleaned.startsWith('```json')) cleaned = cleaned.slice(7);
  else if (cleaned.startsWith('```')) cleaned = cleaned.slice(3);
  if (cleaned.endsWith('```')) cleaned = cleaned.slice(0, -3);
  return cleaned.trim();
}

const router = express.Router();
router.use(authenticate);

router.get(
  '/status/:jobId',
  async (req: Request, res: Response) => {
    const { jobId } = req.params;
    const job = getJob(jobId);

    if (!job) {
      res.status(404).json({ error: 'Job not found' });
      return;
    }

    res.json({
      jobId: job.jobId,
      status: job.status,
      progress: job.progress,
      step: job.step,
      result: job.result,
      error: job.error,
    });
  }
);

// ============================================
// POST /auto-fill
// ============================================

router.post(
  '/auto-fill',
  requirePermission('books', 'ai-generate'),
  [
    body('companyId').notEmpty().withMessage('Company ID is required'),
  ],
  async (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ error: 'Validation failed', details: errors.array() });
      return;
    }

    // The module's popup sends `instructions`; the AI Chat generation flow sends
    // the same brief as `customInstructions`, the name every other module's
    // auto-fill uses. Accept both so one brief works from either surface.
    const { companyId, instructions, customInstructions, language } = req.body;

    try {
      const job = createJob('book', companyId, req.body._moduleId);
      res.status(202).json({ jobId: job.jobId, status: 'processing' });

      setImmediate(async () => {
        try {
          const { Company, BusinessProfile, ICP, Product } = getModels();
          const company = await Company.findById(companyId);
          if (!company) {
            failJob(job.jobId, 'Company not found');
            return;
          }

          let businessProfile: any = null;
          try { businessProfile = await BusinessProfile.findOne({ companyId }); } catch {}

          const companyContexts = await aiContextService.getByCompany(companyId, 'company-creation');
          const latestCompanyContext = companyContexts.find((c: any) => {
            const a = c.analysis?.toObject?.() || c.analysis || {};
            return c.status === 'approved' || a.industryType || a.businessModel || a.businessSummary;
          });

          let icpData: any = null;
          try { icpData = await ICP.findOne({ companyId, isActive: true }).sort({ createdAt: -1 }); } catch {}

          let brandStrategyData: any = null;
          try {
            const { ModuleData } = getModels();
            const brandStrategyDoc = await ModuleData.findOne({ moduleId: 'brand-strategy', companyId });
            if (brandStrategyDoc?.data) {
              brandStrategyData = brandStrategyDoc.data;
            }
          } catch {}

          let productNames: string[] | undefined;
          let productDescriptions: string[] | undefined;
          try {
            const products = await Product.find({ companyId }).limit(10);
            if (products.length > 0) {
              productNames = products.map((p: any) => p.name);
              productDescriptions = products.map((p: any) => p.description || p.shortDescription || '');
            }
          } catch {}

          let founderData: any = null;
          try {
            const { Founder } = getModels();
            founderData = await Founder.findOne({ companyId }).sort({ createdAt: -1 });
          } catch {}

          const pipelineInputs: BookPipelineInputs = {
            companyName: company.name,
            companyDescription: company.description || businessProfile?.description || undefined,
            companyIndustry: businessProfile?.primaryIndustry || undefined,
            companyBusinessModel: businessProfile?.businessModel || undefined,
            companyTargetAudience: undefined,
            companyPrimaryOffering: undefined,
            companyUsps: undefined,
            targetCount: 1,
            customInstructions: instructions || customInstructions || undefined,
            language: language || 'English',
          };

          if (latestCompanyContext) {
            const analysis = (latestCompanyContext as any).analysis?.toObject?.() || (latestCompanyContext as any).analysis || {};
            if (analysis.industryType && !pipelineInputs.companyIndustry) pipelineInputs.companyIndustry = analysis.industryType;
            if (analysis.businessModel && !pipelineInputs.companyBusinessModel) pipelineInputs.companyBusinessModel = analysis.businessModel;
            if (analysis.targetAudience?.primary) pipelineInputs.companyTargetAudience = analysis.targetAudience.primary;
            if (analysis.primaryOffering) pipelineInputs.companyPrimaryOffering = analysis.primaryOffering;
            if (analysis.uspSuggestions?.length) pipelineInputs.companyUsps = analysis.uspSuggestions;
          }

          if (icpData) {
            pipelineInputs.icpName = icpData.name || undefined;
            pipelineInputs.icpIndustry = icpData.industry || undefined;
            pipelineInputs.icpCompanySize = icpData.companySize || undefined;
            pipelineInputs.icpPainPoints = icpData.painPoints || undefined;
            pipelineInputs.icpBusinessGoals = icpData.businessGoals || undefined;
          }

          if (brandStrategyData) {
            pipelineInputs.brandArchetype = brandStrategyData.brandArchetype || undefined;
            pipelineInputs.brandPersonality = brandStrategyData.brandPersonality || undefined;
            pipelineInputs.brandValues = brandStrategyData.brandValues || undefined;
            pipelineInputs.brandPositioning = brandStrategyData.brandPositioning || undefined;
            pipelineInputs.brandVoice = brandStrategyData.brandVoice || undefined;
          }

          if (productNames?.length) {
            pipelineInputs.productNames = productNames;
            pipelineInputs.productDescriptions = productDescriptions;
          }

          if (founderData) {
            pipelineInputs.founderName = founderData.name || undefined;
            pipelineInputs.founderBio = founderData.bio || founderData.shortBio || undefined;
            pipelineInputs.founderExpertise = founderData.expertise || founderData.skills || undefined;
          }

          updateJobProgress(job.jobId, 10, 'Preparing context...');
          const pipeline = new BookPipeline(pipelineInputs, (progress, step) => updateJobProgress(job.jobId, progress, step));
          const result = await pipeline.run();

          // Store full analysis in AiContext
          try {
            const context = await aiContextService.create({
              companyId,
              moduleSource: 'book',
              analysisType: 'full-analysis',
              inputs: { companyName: company.name, description: pipelineInputs.companyDescription } as any,
              analysis: { book: result.book, chapters: result.chapters },
              metadata: {
                pipelineVersion: result.pipelineVersion,
                provider: result.provider,
                model: result.aiModel,
                tokensUsed: result.tokensUsed,
                inputTokens: result.inputTokens,
                outputTokens: result.outputTokens,
                processingTimeMs: result.processingTimeMs,
                latencyMs: result.latencyMs,
                overallConfidence: result.overallConfidence,
                fieldConfidences: {},
                finishReason: result.finishReason,
                apiKeyMasked: result.apiKeyMasked,
              },
            });
            await aiContextService.updateStatus(context.id, 'approved');
          } catch (ctxErr: any) {
            console.warn(`[Book-AutoFill] AiContext save failed (non-fatal): ${ctxErr.message}`);
          }

          // Map through the auto-fill mapping
          const autoFillData = computeBookAutoFillMapping(result.book);
          const chaptersData = result.chapters.map((ch: any) => ({
            ...ch,
            order: typeof ch.order === 'number' ? ch.order : result.chapters.indexOf(ch),
          }));

          // Store the user-selected language as contentLanguage (not language, which conflicts with MongoDB text index)
          if (language) {
            autoFillData.contentLanguage = language;
          }

          completeJob(job.jobId, { books: [autoFillData], chapters: chaptersData }, 'generated');
          console.log(`[Book-AutoFill] Job ${job.jobId} completed. Book generated with ${chaptersData.length} chapters.`);
        } catch (err: any) {
          console.error(`[Book-AutoFill] Job ${job.jobId} failed:`, err.message);
          failJob(job.jobId, err.message || 'AI generation failed');
        }
      });
    } catch (error: any) {
      console.error('[Book-AutoFill] Error:', error.message);
      res.status(500).json({ error: 'Failed to generate book concept', details: error.message });
    }
  }
);

// ============================================
// POST /regenerate
// ============================================

router.post(
  '/regenerate',
  requirePermission('books', 'ai-generate'),
  [
    body('companyId').notEmpty().withMessage('Company ID is required'),
  ],
  async (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ error: 'Validation failed', details: errors.array() });
      return;
    }

    const { companyId, language } = req.body;

    const job = createJob('book', companyId, req.body._moduleId);
    res.status(202).json({ jobId: job.jobId, status: 'processing' });

    setImmediate(async () => {
      try {
        const { Company, BusinessProfile, ICP, Product } = getModels();
        const company = await Company.findById(companyId);
        if (!company) {
          failJob(job.jobId, 'Company not found');
          return;
        }

        let businessProfile: any = null;
        try { businessProfile = await BusinessProfile.findOne({ companyId }); } catch {}

        const companyContexts = await aiContextService.getByCompany(companyId, 'company-creation');
        const latestCompanyContext = companyContexts.find((c: any) => {
          const a = c.analysis?.toObject?.() || c.analysis || {};
          return c.status === 'approved' || a.industryType || a.businessModel || a.businessSummary;
        });

        let icpData: any = null;
        try { icpData = await ICP.findOne({ companyId, isActive: true }).sort({ createdAt: -1 }); } catch {}

        let brandStrategyData: any = null;
        try {
          const { ModuleData } = getModels();
          const brandStrategyDoc = await ModuleData.findOne({ moduleId: 'brand-strategy', companyId });
          if (brandStrategyDoc?.data) {
            brandStrategyData = brandStrategyDoc.data;
          }
        } catch {}

        let productNames: string[] | undefined;
        let productDescriptions: string[] | undefined;
        try {
          const products = await Product.find({ companyId }).limit(10);
          if (products.length > 0) {
            productNames = products.map((p: any) => p.name);
            productDescriptions = products.map((p: any) => p.description || p.shortDescription || '');
          }
        } catch {}

        let founderData: any = null;
        try {
          const { Founder } = getModels();
          founderData = await Founder.findOne({ companyId }).sort({ createdAt: -1 });
        } catch {}

        const pipelineInputs: BookPipelineInputs = {
          companyName: company.name,
          companyDescription: company.description || businessProfile?.description || undefined,
          companyIndustry: businessProfile?.primaryIndustry || undefined,
          companyBusinessModel: businessProfile?.businessModel || undefined,
          targetCount: 1,
          language: language || 'English',
        };

        if (latestCompanyContext) {
          const analysis = (latestCompanyContext as any).analysis?.toObject?.() || (latestCompanyContext as any).analysis || {};
          if (analysis.industryType && !pipelineInputs.companyIndustry) pipelineInputs.companyIndustry = analysis.industryType;
          if (analysis.businessModel && !pipelineInputs.companyBusinessModel) pipelineInputs.companyBusinessModel = analysis.businessModel;
          if (analysis.targetAudience?.primary) pipelineInputs.companyTargetAudience = analysis.targetAudience.primary;
          if (analysis.primaryOffering) pipelineInputs.companyPrimaryOffering = analysis.primaryOffering;
          if (analysis.uspSuggestions?.length) pipelineInputs.companyUsps = analysis.uspSuggestions;
        }

        if (icpData) {
          pipelineInputs.icpName = icpData.name || undefined;
          pipelineInputs.icpIndustry = icpData.industry || undefined;
          pipelineInputs.icpCompanySize = icpData.companySize || undefined;
          pipelineInputs.icpPainPoints = icpData.painPoints || undefined;
          pipelineInputs.icpBusinessGoals = icpData.businessGoals || undefined;
        }

        if (brandStrategyData) {
          pipelineInputs.brandArchetype = brandStrategyData.brandArchetype || undefined;
          pipelineInputs.brandPersonality = brandStrategyData.brandPersonality || undefined;
          pipelineInputs.brandValues = brandStrategyData.brandValues || undefined;
          pipelineInputs.brandPositioning = brandStrategyData.brandPositioning || undefined;
          pipelineInputs.brandVoice = brandStrategyData.brandVoice || undefined;
        }

        if (productNames?.length) {
          pipelineInputs.productNames = productNames;
          pipelineInputs.productDescriptions = productDescriptions;
        }

        if (founderData) {
          pipelineInputs.founderName = founderData.name || undefined;
          pipelineInputs.founderBio = founderData.bio || founderData.shortBio || undefined;
          pipelineInputs.founderExpertise = founderData.expertise || founderData.skills || undefined;
        }

        updateJobProgress(job.jobId, 10, 'Preparing context...');
        const pipeline = new BookPipeline(pipelineInputs, (progress, step) => updateJobProgress(job.jobId, progress, step));
        const result = await pipeline.run();

        const autoFillData = computeBookAutoFillMapping(result.book);
        const chaptersData = result.chapters.map((ch: any) => ({
          ...ch,
          order: typeof ch.order === 'number' ? ch.order : result.chapters.indexOf(ch),
        }));

        // Store the user-selected language as contentLanguage (not language, which conflicts with MongoDB text index)
        if (language) {
          autoFillData.contentLanguage = language;
        }

        completeJob(job.jobId, { books: [autoFillData], chapters: chaptersData }, 'regenerated');
        console.log(`[Book-Regenerate] Job ${job.jobId} completed.`);
      } catch (err: any) {
        console.error(`[Book-Regenerate] Job ${job.jobId} failed:`, err.message);
        failJob(job.jobId, err.message || 'AI regeneration failed');
      }
    });
  }
);

// ============================================
// POST /translate-content
// ============================================

router.post(
  '/translate-content',
  requirePermission('books', 'ai-generate'),
  [
    body('companyId').notEmpty().withMessage('Company ID is required'),
  ],
  async (req: Request, res: Response) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      res.status(400).json({ error: 'Validation failed', details: errors.array() });
      return;
    }

    const { companyId, fields, language, bookId, mode } = req.body;

    if (!language || typeof language !== 'string') {
      res.status(400).json({ error: 'Language is required' });
      return;
    }
    if (!fields || typeof fields !== 'object' || Object.keys(fields).length === 0) {
      res.status(400).json({ error: 'Fields object with at least one text field is required' });
      return;
    }

    try {
      const job = createJob('book', companyId, req.body._moduleId);
      res.status(202).json({ jobId: job.jobId, status: 'processing' });

      setImmediate(async () => {
        try {
          updateJobProgress(job.jobId, 10, `Translating content to ${language}...`);

          const { systemPrompt, userPrompt, maxTokens } = buildTranslateContentPrompt(fields, language);
          const userId = req.user?._id?.toString() || req.user?.id;
          const content = await generateBookAI(userPrompt, systemPrompt, maxTokens, userId);

          updateJobProgress(job.jobId, 80, 'Processing translation...');

          // Parse the AI response
          let translatedFields: Record<string, string> = {};
          try {
            let cleaned = content.trim();
            if (cleaned.startsWith('```json')) cleaned = cleaned.slice(7);
            else if (cleaned.startsWith('```')) cleaned = cleaned.slice(3);
            if (cleaned.endsWith('```')) cleaned = cleaned.slice(0, -3);
            cleaned = cleaned.trim();
            translatedFields = JSON.parse(cleaned);
          } catch (parseErr: any) {
            console.error(`[Book-Translate] Failed to parse translation for job ${job.jobId}:`, parseErr.message);
            failJob(job.jobId, 'Failed to parse translation result');
            return;
          }

          // Strip 'language' key from translatedFields to prevent MongoDB text index conflict
          // (MongoDB treats 'language' as a special text search override field)
          if ('language' in translatedFields) {
            delete translatedFields.language;
          }

          updateJobProgress(job.jobId, 90, 'Finalizing...');

          completeJob(job.jobId, {
            translatedFields,
            language,
            bookId: bookId || null,
            mode: mode || 'create',
          }, 'translated');

          console.log(`[Book-Translate] Job ${job.jobId} completed. Translated to ${language}.`);
        } catch (err: any) {
          console.error(`[Book-Translate] Job ${job.jobId} failed:`, err.message);
          failJob(job.jobId, err.message || 'Translation failed');
        }
      });
    } catch (error: any) {
      console.error('[Book-Translate] Error:', error.message);
      res.status(500).json({ error: 'Failed to start translation', details: error.message });
    }
  }
);

export default router;