import { NextResponse } from 'next/server';
import { z } from 'zod';
import { GeminiLlmClient } from '@/lib/ai/gemini-client';
import type { LlmClient } from '@/lib/ai/llm-client';
import { query } from '@/lib/db-postgres';
import { MODE_SYSTEM_PROMPTS, ChatMode } from '@/lib/ai/chat-modes';
import { resolveChatMode } from '@/lib/server/chat-mode-resolver';
import {
  buildProjectContextForChat,
  determineArtifactsUsed,
  formatContextForPrompt,
} from '@/lib/server/chat-context';
import { logProjectEvent } from '@/lib/server/logs';
import type { CollectorPhaseHandoff } from '@/lib/types/phase-handoff';

// Increase timeout for Gemini 3 Pro thinking mode (can take 1-2 minutes)
export const maxDuration = 180; // 3 minutes
export const dynamic = 'force-dynamic';

const ChatReplySchema = z.object({
  reply: z.string(),
  visionAnswers: z.object({
    q1: z.string().optional(), // Answer to question 1
    q2: z.string().optional(), // Answer to question 2
    q3: z.string().optional(), // Answer to question 3
    allAnswered: z.boolean().optional(), // True when all 3 are complete
  }).optional(),
  collectorHandoff: z.object({
    hasDocuments: z.boolean().optional(),
    documentCount: z.number().optional(),
    githubConnected: z.boolean().optional(),
    githubRepo: z.string().optional(),
    extensionLinked: z.boolean().optional(),
    extensionDeclined: z.boolean().optional(),
    noGithubYet: z.boolean().optional(),
    readyForExtraction: z.boolean().optional(),
  }).optional(),
  extractionReviewHandoff: z.object({
    extractionApproved: z.boolean().optional(),
    readyForVision: z.boolean().optional(),
  }).optional(),
});

interface ChatRequestBody {
  projectId?: string;
  message?: string;
  overrideMode?: ChatMode;
}

const ENSURE_CONV_TABLE = `
  CREATE TABLE IF NOT EXISTS chat_conversations (
    project_id text PRIMARY KEY,
    messages    jsonb NOT NULL DEFAULT '[]',
    updated_at  timestamptz NOT NULL DEFAULT NOW()
  )
`;

async function appendConversation(
  projectId: string,
  newMessages: Array<{ role: 'user' | 'assistant'; content: string }>,
) {
  await query(ENSURE_CONV_TABLE);
  const now = new Date().toISOString();
  const stamped = newMessages.map((m) => ({ ...m, createdAt: now }));

  await query(
    `INSERT INTO chat_conversations (project_id, messages, updated_at)
     VALUES ($1, $2::jsonb, NOW())
     ON CONFLICT (project_id) DO UPDATE
       SET messages   = chat_conversations.messages || $2::jsonb,
           updated_at = NOW()`,
    [projectId, JSON.stringify(stamped)]
  );
}

export async function POST(request: Request) {
  try {
    const body = (await request.json()) as ChatRequestBody;
    const projectId = body.projectId?.trim();
    const message = body.message?.trim();

    if (!projectId || !message) {
      return NextResponse.json({ error: 'projectId and message are required' }, { status: 400 });
    }

    // Verify project exists in Postgres
    const projectRows = await query<{ data: any }>(
      `SELECT data FROM fs_projects WHERE id = $1 LIMIT 1`,
      [projectId]
    );
    if (projectRows.length === 0) {
      return NextResponse.json({ error: 'Project not found' }, { status: 404 });
    }
    const projectData = projectRows[0].data ?? {};

    // Resolve chat mode (uses new resolver)
    const resolvedMode = body.overrideMode ?? await resolveChatMode(projectId);
    console.log(`[AI Chat] Mode: ${resolvedMode}`);

    // Build comprehensive context with vector retrieval
    // Only include GitHub analysis for MVP generation (not needed for vision questions)
    const context = await buildProjectContextForChat(projectId, resolvedMode, message, {
      retrievalLimit: 10,
      includeVectorSearch: true,
      includeGitHubAnalysis: resolvedMode === 'mvp_mode', // Only load repo analysis when generating MVP
    });

    console.log(`[AI Chat] Context built: ${context.retrievedChunks.length} vector chunks retrieved`);

    // Get mode-specific system prompt
    const systemPrompt = MODE_SYSTEM_PROMPTS[resolvedMode];

    // Format context for LLM
    const contextSummary = formatContextForPrompt(context);

    // Prepare enhanced system prompt with context
    const enhancedSystemPrompt = `${systemPrompt}

## Current Project Context

${contextSummary}

---

You have access to:
- Project artifacts (product model, MVP plan, marketing plan)
- Knowledge items (${context.knowledgeSummary.totalCount} total)
- Extraction signals (${context.extractionSummary.totalCount} analyzed)
${context.retrievedChunks.length > 0 ? `- ${context.retrievedChunks.length} relevant chunks from vector search (most similar to user's query)` : ''}
${context.repositoryAnalysis ? `- GitHub repository analysis (${context.repositoryAnalysis.totalFiles} files)` : ''}
${context.sessionHistory.totalSessions > 0 ? `- Complete Cursor session history (${context.sessionHistory.totalSessions} sessions, ${context.sessionHistory.messages.length} messages in chronological order)` : ''}

Use this context to provide specific, grounded responses. The session history shows your complete conversation history with the user - use it to understand what has been built and discussed.`;

    // Load existing conversation history from Postgres
    await query(ENSURE_CONV_TABLE);
    const convRows = await query<{ messages: any[] }>(
      `SELECT messages FROM chat_conversations WHERE project_id = $1`,
      [projectId]
    );
    const conversationHistory: any[] = convRows[0]?.messages ?? [];

    // Build full message context (history + current message)
    const messages = [
      ...conversationHistory.map((msg: any) => ({
        role: msg.role as 'user' | 'assistant',
        content: msg.content as string,
      })),
      {
        role: 'user' as const,
        content: message,
      },
    ];

    console.log(`[AI Chat] Sending ${messages.length} messages to LLM (${conversationHistory.length} from history + 1 new)`);
    console.log(`[AI Chat] Mode: ${resolvedMode}, Phase: ${projectData.currentPhase}, Has extraction: ${!!context.phaseHandoffs?.extraction}`);
    
    // Log system prompt length
    console.log(`[AI Chat] System prompt length: ${enhancedSystemPrompt.length} chars (~${Math.ceil(enhancedSystemPrompt.length / 4)} tokens)`);
    
    // Log each message length
    messages.forEach((msg, i) => {
      console.log(`[AI Chat] Message ${i + 1} (${msg.role}): ${msg.content.length} chars (~${Math.ceil(msg.content.length / 4)} tokens)`);
    });
    
    const totalInputChars = enhancedSystemPrompt.length + messages.reduce((sum, msg) => sum + msg.content.length, 0);
    console.log(`[AI Chat] Total input: ${totalInputChars} chars (~${Math.ceil(totalInputChars / 4)} tokens)`);
    
    // Log system prompt preview (first 500 chars)
    console.log(`[AI Chat] System prompt preview: ${enhancedSystemPrompt.substring(0, 500)}...`);
    
    // Log last user message
    const lastUserMsg = messages[messages.length - 1];
    console.log(`[AI Chat] User message: ${lastUserMsg.content}`);
    
    // Safety check: extraction_review_mode requires extraction results
    if (resolvedMode === 'extraction_review_mode' && !context.phaseHandoffs?.extraction) {
      console.warn(`[AI Chat] WARNING: extraction_review_mode active but no extraction results found for project ${projectId}`);
    }

    const llm: LlmClient = new GeminiLlmClient();

    // Configure thinking mode based on task complexity
    // Simple modes (collector, extraction_review) don't need deep thinking
    // Complex modes (mvp, vision) benefit from extended reasoning
    const needsThinking = resolvedMode === 'mvp_mode' || resolvedMode === 'vision_mode';

    const reply = await llm.structuredCall<{ 
      reply: string;
      visionAnswers?: {
        q1?: string;
        q2?: string;
        q3?: string;
        allAnswered?: boolean;
      };
      collectorHandoff?: {
        hasDocuments?: boolean;
        documentCount?: number;
        githubConnected?: boolean;
        githubRepo?: string;
        extensionLinked?: boolean;
        extensionDeclined?: boolean;
        noGithubYet?: boolean;
        readyForExtraction?: boolean;
      };
      extractionReviewHandoff?: {
        extractionApproved?: boolean;
        readyForVision?: boolean;
      };
    }>({
      model: 'gemini',
      systemPrompt: enhancedSystemPrompt,
      messages: messages,  // Full conversation history!
      schema: ChatReplySchema,
      temperature: 0.4,
      thinking_config: needsThinking ? {
        thinking_level: 'high',
        include_thoughts: false,
      } : undefined,
    });

    // Store all vision answers when provided
    if (reply.visionAnswers) {
      const updates: any = {};
      
      if (reply.visionAnswers.q1) {
        updates['visionAnswers.q1'] = reply.visionAnswers.q1;
        console.log('[AI Chat] Storing vision answer Q1');
      }
      if (reply.visionAnswers.q2) {
        updates['visionAnswers.q2'] = reply.visionAnswers.q2;
        console.log('[AI Chat] Storing vision answer Q2');
      }
      if (reply.visionAnswers.q3) {
        updates['visionAnswers.q3'] = reply.visionAnswers.q3;
        console.log('[AI Chat] Storing vision answer Q3');
      }
      
      // If all answers are complete, trigger MVP generation
      if (reply.visionAnswers.allAnswered) {
        updates['visionAnswers.allAnswered'] = true;
        updates['readyForMVP'] = true;
        console.log('[AI Chat] ✅ All 3 vision answers complete - ready for MVP generation');
      }
      
      if (Object.keys(updates).length > 0) {
        updates['visionAnswers.updatedAt'] = new Date().toISOString();
        
        await query(
          `UPDATE fs_projects
           SET data = data || $1::jsonb
           WHERE id = $2`,
          [JSON.stringify({ visionAnswers: updates }), projectId]
        ).catch((error) => {
          console.error('[ai/chat] Failed to store vision answers', error);
        });
      }
    }

    // Best-effort: append this turn to the persisted conversation history
    appendConversation(projectId, [
      { role: 'user', content: message },
      { role: 'assistant', content: reply.reply },
    ]).catch((error) => {
      console.error('[ai/chat] Failed to append conversation history', error);
    });

    // If in collector mode, always update handoff state based on actual project context
    // This ensures the checklist updates even if AI doesn't return collectorHandoff
    if (resolvedMode === 'collector_mode') {
      // Derive handoff state from actual project context
      const hasDocuments = (context.knowledgeSummary.bySourceType['imported_document'] ?? 0) > 0;
      const documentCount = context.knowledgeSummary.bySourceType['imported_document'] ?? 0;
      const githubConnected = !!context.project.githubRepo;
      const extensionLinked = context.project.extensionLinked ?? false;

      // Check if AI indicated readiness (from reply if provided, otherwise check reply text)
      let readyForExtraction = reply.collectorHandoff?.readyForExtraction ?? false;
      
      // Fallback: If AI says certain phrases, assume user confirmed readiness
      // IMPORTANT: These phrases must be SPECIFIC to avoid false positives
      if (!readyForExtraction && reply.reply) {
        const replyLower = reply.reply.toLowerCase();
        
        // Check for explicit analysis/digging phrases (not just "perfect!")
        const analysisKeywords = ['analyze', 'analyzing', 'digging', 'extraction', 'processing'];
        const hasAnalysisKeyword = analysisKeywords.some(keyword => replyLower.includes(keyword));
        
        // Only trigger if AI mentions BOTH readiness AND analysis action
        if (hasAnalysisKeyword) {
          const confirmPhrases = [
            'let me analyze what you',
            'i\'ll start digging into',
            'i\'m starting the analysis',
            'running the extraction',
            'processing what you\'ve shared',
          ];
          readyForExtraction = confirmPhrases.some(phrase => replyLower.includes(phrase));
          
          if (readyForExtraction) {
            console.log(`[AI Chat] Detected readiness from AI reply text: "${reply.reply.substring(0, 100)}"`);
          }
        }
      }

      const handoff: CollectorPhaseHandoff = {
        phase: 'collector',
        readyForNextPhase: readyForExtraction,
        confidence: readyForExtraction ? 0.9 : 0.5,
        confirmed: {
          hasDocuments,
          documentCount,
          githubConnected,
          githubRepo: context.project.githubRepo ?? undefined,
          extensionLinked,
        },
        uncertain: {
          extensionDeclined: reply.collectorHandoff?.extensionDeclined ?? false,
          noGithubYet: reply.collectorHandoff?.noGithubYet ?? false,
        },
        missing: [],
        questionsForUser: [],
        sourceEvidence: [],
        version: '1.0',
        timestamp: new Date().toISOString(),
      };

      // Persist to project phaseData in Postgres
      await query(
        `UPDATE fs_projects
         SET data = jsonb_set(
           data,
           '{phaseData,phaseHandoffs,collector}',
           $1::jsonb,
           true
         )
         WHERE id = $2`,
        [JSON.stringify(handoff), projectId]
      ).catch((error) => {
        console.error('[ai/chat] Failed to persist collector handoff', error);
      });

      console.log(`[AI Chat] Collector handoff persisted:`, {
        hasDocuments: handoff.confirmed.hasDocuments,
        githubConnected: handoff.confirmed.githubConnected,
        extensionLinked: handoff.confirmed.extensionLinked,
        readyForExtraction: handoff.readyForNextPhase,
      });

      // Auto-transition to extraction phase if ready
      if (handoff.readyForNextPhase) {
        console.log(`[AI Chat] Collector complete - triggering backend extraction`);
        
        // Mark collector as complete
        await query(
          `UPDATE fs_projects
           SET data = jsonb_set(data, '{phaseData,collectorCompletedAt}', $1::jsonb, true)
           WHERE id = $2`,
          [JSON.stringify(new Date().toISOString()), projectId]
        ).catch((error) => {
          console.error('[ai/chat] Failed to mark collector complete', error);
        });
        
        // Trigger backend extraction (async - don't await)
        import('@/lib/server/backend-extractor').then(({ runBackendExtractionForProject }) => {
          runBackendExtractionForProject(projectId).catch((error) => {
            console.error(`[AI Chat] Backend extraction failed for project ${projectId}:`, error);
          });
        });
      }
    }

    // Handle extraction review → vision phase transition
    if (resolvedMode === 'extraction_review_mode') {
      // Check if AI indicated extraction is approved and ready for vision
      let readyForVision = reply.extractionReviewHandoff?.readyForVision ?? false;
      
      // Fallback: Check reply text for approval phrases
      if (!readyForVision && reply.reply) {
        const replyLower = reply.reply.toLowerCase();
        
        // Check for vision transition phrases
        const visionKeywords = ['vision', 'mvp', 'roadmap', 'plan'];
        const hasVisionKeyword = visionKeywords.some(keyword => replyLower.includes(keyword));
        
        if (hasVisionKeyword) {
          const confirmPhrases = [
            'ready to move to',
            'ready for vision',
            'let\'s move to vision',
            'moving to vision',
            'great! let\'s define',
            'perfect! now let\'s',
          ];
          readyForVision = confirmPhrases.some(phrase => replyLower.includes(phrase));
          
          if (readyForVision) {
            console.log(`[AI Chat] Detected vision readiness from AI reply text: "${reply.reply.substring(0, 100)}"`);
          }
        }
      }
      
      if (readyForVision) {
        console.log(`[AI Chat] Extraction review complete - transitioning to vision phase`);
        
        // Mark extraction review as complete and transition to vision
        await query(
          `UPDATE fs_projects
           SET data = data
             || '{"currentPhase":"vision","phaseStatus":"in_progress"}'::jsonb
             || jsonb_build_object('phaseData',
                  (data->'phaseData') || jsonb_build_object(
                    'extractionReviewCompletedAt', $1::text
                  )
                )
           WHERE id = $2`,
          [new Date().toISOString(), projectId]
        ).catch((error) => {
          console.error('[ai/chat] Failed to transition to vision phase', error);
        });
      }
    }

    // Save conversation history to Postgres
    await appendConversation(projectId, [
      { role: 'user', content: message },
      { role: 'assistant', content: reply.reply },
    ]).catch((error) => {
      console.error('[ai/chat] Failed to save conversation history', error);
    });

    console.log(`[AI Chat] Conversation history saved (+2 messages)`);

    // Determine which artifacts were used
    const artifactsUsed = determineArtifactsUsed(context);

    // Log successful interaction
    logProjectEvent({
      projectId,
      userId: projectData.userId ?? null,
      eventType: 'chat_interaction',
      mode: resolvedMode,
      phase: projectData.currentPhase ?? null,
      artifactsUsed,
      usedVectorSearch: context.retrievedChunks.length > 0,
      vectorChunkCount: context.retrievedChunks.length,
      promptVersion: '2.0', // Updated with vector search
      modelUsed: process.env.VERTEX_AI_MODEL || 'gemini-3-pro-preview',
      success: true,
      errorMessage: null,
      metadata: {
        knowledgeCount: context.knowledgeSummary.totalCount,
        extractionCount: context.extractionSummary.totalCount,
        hasGithubRepo: !!context.repositoryAnalysis,
      },
    }).catch((err) => console.error('[ai/chat] Failed to log event:', err));

    return NextResponse.json({
      reply: reply.reply,
      mode: resolvedMode,
      projectPhase: projectData.currentPhase ?? null,
      artifactsUsed,
      usedVectorSearch: context.retrievedChunks.length > 0,
    });
  } catch (error) {
    console.error('[ai/chat] Error handling chat request', error);

    // Log error (best-effort) - extract projectId from request body if available
    const errorProjectId = typeof (error as { projectId?: string })?.projectId === 'string' 
      ? (error as { projectId: string }).projectId 
      : null;
    
    if (errorProjectId) {
      logProjectEvent({
        projectId: errorProjectId,
        userId: null,
        eventType: 'error',
        mode: null,
        phase: null,
        artifactsUsed: [],
        usedVectorSearch: false,
        promptVersion: '2.0',
        modelUsed: process.env.VERTEX_AI_MODEL || 'gemini-3-pro-preview',
        success: false,
        errorMessage: error instanceof Error ? error.message : String(error),
      }).catch((err) => console.error('[ai/chat] Failed to log error:', err));
    }

    return NextResponse.json(
      {
        error: 'Failed to process chat message',
        details: error instanceof Error ? error.message : String(error),
      },
      { status: 500 },
    );
  }
}


