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 logSchema = z.object({
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  weightKg: z.number().min(20).max(400).optional(),
  calories: z.number().min(0).max(10000).optional(),
  proteinG: z.number().min(0).max(500).optional(),
  fatG: z.number().min(0).max(500).optional(),
  carbsG: z.number().min(0).max(500).optional(),
  netCarbsG: z.number().min(0).max(100).optional(),
  waterMl: z.number().min(0).max(10000).optional(),
  notes: z.string().max(500).optional()
});

// POST /api/tracker/log - create or update daily log
router.post('/log', async (req: AuthRequest, res: Response) => {
  try {
    const body = logSchema.parse(req.body);
    const dateStr = body.date || new Date().toISOString().split('T')[0];
    const date = new Date(dateStr + 'T12:00:00Z');

    const log = await prisma.progressLog.upsert({
      where: { userId_date: { userId: req.user!.id, date } },
      create: { userId: req.user!.id, date, ...body },
      update: body
    });

    // Check achievements after logging
    await checkAchievements(req.user!.id);

    res.json({ log });
  } catch (err: any) {
    if (err instanceof z.ZodError) return res.status(400).json({ error: 'Validation error', details: err.errors });
    res.status(500).json({ error: 'Failed to save log' });
  }
});

// GET /api/tracker/logs - get logs for date range
router.get('/logs', async (req: AuthRequest, res: Response) => {
  try {
    const { from, to } = z.object({
      from: z.string().optional(),
      to: z.string().optional()
    }).parse(req.query);

    const fromDate = from ? new Date(from) : new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
    const toDate = to ? new Date(to) : new Date();

    const logs = await prisma.progressLog.findMany({
      where: {
        userId: req.user!.id,
        date: { gte: fromDate, lte: toDate }
      },
      orderBy: { date: 'asc' }
    });

    res.json({ logs });
  } catch {
    res.status(500).json({ error: 'Failed to fetch logs' });
  }
});

// GET /api/tracker/summary - weekly/monthly summary stats
router.get('/summary', async (req: AuthRequest, res: Response) => {
  try {
    const user = await prisma.user.findUnique({
      where: { id: req.user!.id },
      select: { weightKg: true, targetWeightKg: true, streakCount: true, totalPoints: true }
    });

    const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
    const logs = await prisma.progressLog.findMany({
      where: { userId: req.user!.id, date: { gte: thirtyDaysAgo } },
      orderBy: { date: 'asc' }
    });

    const achievements = await prisma.userAchievement.findMany({
      where: { userId: req.user!.id },
      include: { achievement: true },
      orderBy: { earnedAt: 'desc' },
      take: 5
    });

    const weightLogs = logs.filter(l => l.weightKg);
    const firstWeight = weightLogs[0]?.weightKg;
    const lastWeight = weightLogs[weightLogs.length - 1]?.weightKg;
    const weightLost = firstWeight && lastWeight ? firstWeight - lastWeight : 0;

    const avgCalories = logs.length > 0
      ? Math.round(logs.filter(l => l.calories).reduce((sum, l) => sum + (l.calories || 0), 0) / logs.filter(l => l.calories).length)
      : 0;

    res.json({
      user,
      stats: {
        logsCount: logs.length,
        weightLost: Math.round(weightLost * 10) / 10,
        avgCalories,
        currentStreak: user?.streakCount || 0
      },
      recentAchievements: achievements.map(a => ({
        name: a.achievement.name,
        icon: a.achievement.icon,
        earnedAt: a.earnedAt
      }))
    });
  } catch {
    res.status(500).json({ error: 'Failed to fetch summary' });
  }
});

// Helper: check and award achievements
async function checkAchievements(userId: string) {
  try {
    const user = await prisma.user.findUnique({
      where: { id: userId },
      select: { streakCount: true, totalPoints: true }
    });

    const allAchievements = await prisma.achievement.findMany();
    const earned = await prisma.userAchievement.findMany({
      where: { userId },
      select: { achievementId: true }
    });
    const earnedIds = new Set(earned.map(e => e.achievementId));

    const logsCount = await prisma.progressLog.count({ where: { userId } });
    const purchaseCount = await prisma.purchase.count({ where: { userId } });

    for (const achievement of allAchievements) {
      if (earnedIds.has(achievement.id)) continue;

      const condition = achievement.condition as any;
      let earned = false;

      if (condition.type === 'streak' && (user?.streakCount || 0) >= condition.value) earned = true;
      if (condition.type === 'logs' && logsCount >= condition.value) earned = true;
      if (condition.type === 'purchases' && purchaseCount >= condition.value) earned = true;

      if (earned) {
        await prisma.userAchievement.create({
          data: { userId, achievementId: achievement.id }
        });
        await prisma.user.update({
          where: { id: userId },
          data: { totalPoints: { increment: achievement.points } }
        });
      }
    }
  } catch (err) {
    console.error('Achievement check failed:', err);
  }
}

export { router as trackerRouter };
