import { requireAuth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { NextResponse } from "next/server";

const STREAK_REWARDS: Record<number, number> = {
  1: 100,
  3: 300,
  7: 500,
  14: 1000,
  30: 2500,
};

function getStreakReward(streak: number): number {
  const milestones = Object.keys(STREAK_REWARDS)
    .map(Number)
    .sort((a, b) => b - a);
  for (const m of milestones) {
    if (streak >= m) return STREAK_REWARDS[m];
  }
  return 0;
}

function getXpForStreakClaim(streak: number): number {
  return Math.min(10 + streak * 2, 100);
}

function isYesterday(d: Date): boolean {
  const now = new Date();
  const yesterday = new Date(now);
  yesterday.setDate(yesterday.getDate() - 1);
  return (
    d.getFullYear() === yesterday.getFullYear() &&
    d.getMonth() === yesterday.getMonth() &&
    d.getDate() === yesterday.getDate()
  );
}

function isToday(d: Date): boolean {
  const now = new Date();
  return (
    d.getFullYear() === now.getFullYear() &&
    d.getMonth() === now.getMonth() &&
    d.getDate() === now.getDate()
  );
}

// GET /api/gamification/streak — get current streak info
export async function GET(request: Request) {
  const jwt = await requireAuth(request);
  if (!jwt) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  let streak = await prisma.dailyStreak.findUnique({
    where: { userId: jwt.userId },
  });

  if (!streak) {
    streak = await prisma.dailyStreak.create({
      data: { userId: jwt.userId },
    });
  }

  const canClaim =
    !streak.lastClaimDate || !isToday(streak.lastClaimDate);

  const todayReward = getStreakReward(streak.currentStreak + (canClaim ? 1 : 0));

  return NextResponse.json({
    currentStreak: streak.currentStreak,
    longestStreak: streak.longestStreak,
    lastClaimDate: streak.lastClaimDate,
    canClaim,
    streakFreeze: streak.streakFreeze,
    todayReward,
  });
}

// POST /api/gamification/streak — claim daily streak reward
export async function POST(request: Request) {
  const jwt = await requireAuth(request);
  if (!jwt) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const userId = jwt.userId;

  // Get or create streak record
  let streak = await prisma.dailyStreak.findUnique({
    where: { userId },
  });

  if (!streak) {
    streak = await prisma.dailyStreak.create({
      data: { userId },
    });
  }

  // Already claimed today
  if (streak.lastClaimDate && isToday(streak.lastClaimDate)) {
    return NextResponse.json(
      { error: "Already claimed today" },
      { status: 409 }
    );
  }

  let newStreak: number;
  let newLongest: number;

  if (!streak.lastClaimDate) {
    // First claim ever
    newStreak = 1;
    newLongest = 1;
  } else if (isYesterday(streak.lastClaimDate)) {
    // Consecutive day
    newStreak = streak.currentStreak + 1;
    newLongest = Math.max(newStreak, streak.longestStreak);
  } else {
    // Gap > 1 day — check streak freeze
    if (streak.streakFreeze > 0) {
      // Use a freeze — keep streak intact
      newStreak = streak.currentStreak + 1;
      newLongest = Math.max(newStreak, streak.longestStreak);
      // Decrement freeze
      await prisma.dailyStreak.update({
        where: { userId },
        data: { streakFreeze: { decrement: 1 } },
      });
    } else {
      // Reset streak
      newStreak = 1;
      newLongest = streak.longestStreak; // keep longest
    }
  }

  const reward = getStreakReward(newStreak);
  const xpGain = getXpForStreakClaim(newStreak);

  // Update streak
  await prisma.dailyStreak.update({
    where: { userId },
    data: {
      currentStreak: newStreak,
      longestStreak: newLongest,
      lastClaimDate: new Date(),
    },
  });

  // Award FLH
  if (reward > 0) {
    await prisma.user.update({
      where: { id: userId },
      data: { flhBalance: { increment: reward } },
    });
  }

  // Award XP + create transaction
  const xpTx = await prisma.xpTransaction.create({
    data: {
      userId,
      amount: xpGain,
      reason: "daily_login",
    },
  });

  // Update or create user level
  let userLevel = await prisma.userLevel.findUnique({
    where: { userId },
  });

  if (!userLevel) {
    userLevel = await prisma.userLevel.create({
      data: { userId, xp: xpGain },
    });
  } else {
    userLevel = await prisma.userLevel.update({
      where: { userId },
      data: { xp: { increment: xpGain } },
    });
  }

  // Check level up
  let newLevel = userLevel.level;
  let newXp = userLevel.xp;
  let newXpToNext = userLevel.xpToNext;
  let leveledUp = false;

  while (newXp >= newXpToNext) {
    newXp -= newXpToNext;
    newLevel++;
    newXpToNext = Math.floor(newXpToNext * 1.5);
    leveledUp = true;
  }

  if (leveledUp) {
    await prisma.userLevel.update({
      where: { userId },
      data: {
        level: newLevel,
        xp: newXp,
        xpToNext: newXpToNext,
      },
    });
  }

  // Check achievements
  const achievements: string[] = [];

  // Streak 7 days
  if (newStreak >= 7) {
    const exists = await prisma.achievement.findUnique({
      where: { userId_type: { userId, type: "streak_7" } },
    });
    if (!exists) {
      await prisma.achievement.create({
        data: {
          userId,
          type: "streak_7",
          title: "Week Warrior",
          description: "Maintained a 7-day streak",
          icon: "🔥",
        },
      });
      achievements.push("streak_7");
    }
  }

  // Streak 30 days
  if (newStreak >= 30) {
    const exists = await prisma.achievement.findUnique({
      where: { userId_type: { userId, type: "streak_30" } },
    });
    if (!exists) {
      await prisma.achievement.create({
        data: {
          userId,
          type: "streak_30",
          title: "Monthly Master",
          description: "Maintained a 30-day streak",
          icon: "🏆",
        },
      });
      achievements.push("streak_30");
    }
  }

  // Level 5
  if (newLevel >= 5 && leveledUp) {
    const exists = await prisma.achievement.findUnique({
      where: { userId_type: { userId, type: "level_5" } },
    });
    if (!exists) {
      await prisma.achievement.create({
        data: {
          userId,
          type: "level_5",
          title: "Rising Star",
          description: "Reached level 5",
          icon: "⭐",
        },
      });
      achievements.push("level_5");
    }
  }

  return NextResponse.json({
    currentStreak: newStreak,
    longestStreak: newLongest,
    lastClaimDate: new Date(),
    reward,
    xpGain,
    newLevel: leveledUp ? newLevel : undefined,
    achievements,
  });
}
