import { Router, Response } from 'express';
import { z } from 'zod';
import { PrismaClient } from '@prisma/client';
import { AuthRequest } from '../middleware/auth';

const router = Router();
const prisma = new PrismaClient();

const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434';
const AI_MODEL = process.env.OLLAMA_MODEL || 'llama3:8b';

const plannerInputSchema = z.object({
  weightKg: z.number().min(30).max(300),
  targetWeightKg: z.number().min(30).max(300),
  heightCm: z.number().min(100).max(250),
  age: z.number().min(16).max(100),
  gender: z.enum(['male', 'female', 'other']),
  activityLevel: z.enum(['sedentary', 'light', 'moderate', 'active', 'very_active']),
  allergies: z.array(z.string()).default([]),
  budget: z.enum(['budget', 'medium', 'premium']).default('medium'),
  goal: z.enum(['weight_loss', 'maintenance', 'muscle_gain']).default('weight_loss'),
  durationDays: z.number().min(1).max(30).default(7)
});

// Calculate daily keto macros
function calculateMacros(weight: number, height: number, age: number, gender: string, activity: string, goal: string) {
  // BMR (Mifflin-St Jeor)
  const bmr = gender === 'male'
    ? 10 * weight + 6.25 * height - 5 * age + 5
    : 10 * weight + 6.25 * height - 5 * age - 161;

  const activityMultipliers: Record<string, number> = {
    sedentary: 1.2, light: 1.375, moderate: 1.55, active: 1.725, very_active: 1.9
  };
  const tdee = bmr * (activityMultipliers[activity] || 1.55);

  const calories = goal === 'weight_loss' ? tdee - 500 : goal === 'muscle_gain' ? tdee + 200 : tdee;

  return {
    calories: Math.round(calories),
    proteinG: Math.round(weight * 1.6),       // 1.6g per kg
    fatG: Math.round((calories * 0.70) / 9),  // 70% calories from fat
    carbsG: 20,                                 // Standard keto: 20g net carbs
    netCarbsG: 20
  };
}

function buildKetoPlannerPrompt(input: z.infer<typeof plannerInputSchema>, macros: ReturnType<typeof calculateMacros>): string {
  const allergyStr = input.allergies.length > 0 ? `Avoid: ${input.allergies.join(', ')}.` : '';

  return `You are a professional keto diet nutritionist. Generate a detailed ${input.durationDays}-day keto meal plan.

USER PROFILE:
- Weight: ${input.weightKg}kg, Target: ${input.targetWeightKg}kg
- Goal: ${input.goal.replace('_', ' ')}
- Budget: ${input.budget}
${allergyStr}

DAILY MACRO TARGETS:
- Calories: ${macros.calories} kcal
- Protein: ${macros.proteinG}g
- Fat: ${macros.fatG}g  
- Net Carbs: ${macros.netCarbsG}g (STRICT KETO - no more than 20g)

RESPONSE FORMAT - Return ONLY valid JSON, no other text:
{
  "summary": "Brief personalized intro (2-3 sentences)",
  "dailyMacros": {
    "calories": ${macros.calories},
    "proteinG": ${macros.proteinG},
    "fatG": ${macros.fatG},
    "netCarbsG": ${macros.netCarbsG}
  },
  "days": [
    {
      "day": 1,
      "meals": {
        "breakfast": { "name": "...", "description": "...", "calories": 0, "netCarbsG": 0, "proteinG": 0, "fatG": 0 },
        "lunch": { "name": "...", "description": "...", "calories": 0, "netCarbsG": 0, "proteinG": 0, "fatG": 0 },
        "dinner": { "name": "...", "description": "...", "calories": 0, "netCarbsG": 0, "proteinG": 0, "fatG": 0 },
        "snack": { "name": "...", "description": "...", "calories": 0, "netCarbsG": 0, "proteinG": 0, "fatG": 0 }
      }
    }
  ],
  "shoppingList": {
    "proteins": ["..."],
    "fats": ["..."],
    "vegetables": ["..."],
    "other": ["..."]
  },
  "tips": ["...", "...", "..."]
}`;
}

// Check if user can generate (free: 1/week, premium: unlimited)
async function canGenerate(userId: string, tier: string): Promise<{ allowed: boolean; reason?: string }> {
  if (['PRO', 'LIFETIME'].includes(tier)) return { allowed: true };

  const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
  const recent = await prisma.aiSession.count({
    where: { userId, createdAt: { gte: oneWeekAgo } }
  });

  if (recent >= 1) {
    return { allowed: false, reason: 'Free tier: 1 AI plan per week. Upgrade to Pro for unlimited.' };
  }
  return { allowed: true };
}

// POST /api/ai/generate-plan
router.post('/generate-plan', async (req: AuthRequest, res: Response) => {
  try {
    const user = await prisma.user.findUnique({
      where: { id: req.user!.id },
      select: { subscriptionTier: true }
    });

    const { allowed, reason } = await canGenerate(req.user!.id, user?.subscriptionTier || 'FREE');
    if (!allowed) return res.status(429).json({ error: reason, upgradeRequired: true });

    const input = plannerInputSchema.parse(req.body);
    const macros = calculateMacros(
      input.weightKg, input.heightCm, input.age,
      input.gender, input.activityLevel, input.goal
    );

    const prompt = buildKetoPlannerPrompt(input, macros);

    // Call Ollama
    const ollamaRes = await fetch(`${OLLAMA_URL}/api/generate`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model: AI_MODEL,
        prompt,
        stream: false,
        options: {
          temperature: 0.7,
          num_predict: 4000
        }
      })
    });

    if (!ollamaRes.ok) {
      throw new Error(`Ollama error: ${ollamaRes.status}`);
    }

    const ollamaData = await ollamaRes.json() as any;
    const rawResponse = ollamaData.response || '';

    // Parse JSON from response
    let plan: any;
    try {
      // Extract JSON even if there's surrounding text
      const jsonMatch = rawResponse.match(/\{[\s\S]*\}/);
      plan = JSON.parse(jsonMatch?.[0] || rawResponse);
    } catch {
      throw new Error('AI returned invalid response format');
    }

    // Save session
    const session = await prisma.aiSession.create({
      data: {
        userId: req.user!.id,
        inputParams: input as any,
        outputPlan: plan,
        model: AI_MODEL
      }
    });

    res.json({ sessionId: session.id, plan, macros });

  } catch (err: any) {
    if (err instanceof z.ZodError) return res.status(400).json({ error: 'Invalid input', details: err.errors });
    console.error('AI generate error:', err);
    res.status(500).json({ error: 'Failed to generate plan. Please try again.' });
  }
});

// GET /api/ai/sessions - get user's AI session history
router.get('/sessions', async (req: AuthRequest, res: Response) => {
  try {
    const sessions = await prisma.aiSession.findMany({
      where: { userId: req.user!.id },
      orderBy: { createdAt: 'desc' },
      select: { id: true, createdAt: true, inputParams: true, model: true, pdfUrl: true }
    });
    res.json({ sessions });
  } catch {
    res.status(500).json({ error: 'Failed to fetch sessions' });
  }
});

// GET /api/ai/sessions/:id - get specific session
router.get('/sessions/:id', async (req: AuthRequest, res: Response) => {
  try {
    const session = await prisma.aiSession.findFirst({
      where: { id: req.params.id, userId: req.user!.id }
    });
    if (!session) return res.status(404).json({ error: 'Session not found' });
    res.json({ session });
  } catch {
    res.status(500).json({ error: 'Failed to fetch session' });
  }
});

// GET /api/ai/status - check Ollama availability
router.get('/status', async (_req, res: Response) => {
  try {
    const response = await fetch(`${OLLAMA_URL}/api/tags`);
    const data = await response.json() as any;
    const models = data.models?.map((m: any) => m.name) || [];
    res.json({ available: true, models, recommended: AI_MODEL });
  } catch {
    res.json({ available: false, models: [], error: 'Ollama not reachable' });
  }
});

export { router as aiRouter };
