import { NextRequest, NextResponse } from "next/server";
import { auth } from "@clerk/nextjs/server";
import Database from "better-sqlite3";
import log from "@/lib/logger";

const db = new Database("./data/fitai.db");

interface WeeklyStats {
  week: string; // ISO week start date
  checkIns: number;
  goalsCompleted: number;
  avgProgress: number;
}

interface GoalStats {
  total: number;
  active: number;
  completed: number;
  avgProgress: number;
  byType: Record<string, number>;
}

interface AttendanceStats {
  totalCheckIns: number;
  currentStreak: number;
  longestStreak: number;
  thisWeek: number;
  thisMonth: number;
  recentCheckIns: Array<{
    id: string;
    checkInTime: string; // ISO string
    checkOutTime: string | null;
    type: string;
    duration?: number; // in minutes
  }>;
}

interface DashboardStatistics {
  goals: GoalStats;
  attendance: AttendanceStats;
  weeklyTrend: WeeklyStats[];
}

// GET - Fetch dashboard statistics for authenticated user
export async function GET(request: NextRequest) {
  try {
    // Log the request details for debugging
    log.debug("Statistics endpoint called", {
      url: request.url,
      hasAuthHeader: !!request.headers.get("authorization"),
      authHeaderPreview: request.headers.get("authorization")?.substring(0, 30),
    });

    const { userId: authenticatedUserId } = await auth();

    log.debug("Auth result", {
      authenticatedUserId,
      isAuthenticated: !!authenticatedUserId,
    });

    if (!authenticatedUserId) {
      log.error("Statistics GET - authentication failed", {
        hasAuthHeader: !!request.headers.get("authorization"),
        url: request.url,
      });
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    // Get target user ID from query params, default to authenticated user
    const { searchParams } = new URL(request.url);
    const userId = searchParams.get("userId") || authenticatedUserId;

    // Users can only access their own statistics unless they're staff
    // (we could add role checking here if needed)

    log.debug("Fetching statistics for user", {
      authenticatedUserId,
      targetUserId: userId,
    });

    // Get goal statistics
    const goals = db
      .prepare(
        `SELECT 
          goal_type as goalType,
          status,
          progress,
          target_value as targetValue,
          current_value as currentValue
         FROM fitness_goals 
         WHERE user_id = ?`,
      )
      .all(userId) as Array<{
      goalType: string;
      status: string;
      progress: number;
      targetValue: number | null;
      currentValue: number | null;
    }>;

    const activeGoals = goals.filter((g) => g.status === "active");
    const completedGoals = goals.filter((g) => g.status === "completed");

    const goalsByType: Record<string, number> = {};
    goals.forEach((goal) => {
      goalsByType[goal.goalType] = (goalsByType[goal.goalType] || 0) + 1;
    });

    const avgProgress =
      activeGoals.length > 0
        ? activeGoals.reduce((sum, g) => sum + (g.progress || 0), 0) /
          activeGoals.length
        : 0;

    const goalStats: GoalStats = {
      total: goals.length,
      active: activeGoals.length,
      completed: completedGoals.length,
      avgProgress: Math.round(avgProgress),
      byType: goalsByType,
    };

    // Get attendance statistics
    const attendanceRecords = db
      .prepare(
        `SELECT 
          id,
          check_in_time as checkInTime,
          check_out_time as checkOutTime,
          type
         FROM attendance 
         WHERE user_id = ?
         ORDER BY check_in_time DESC`,
      )
      .all(userId) as Array<{
      id: string;
      checkInTime: string | number; // Can be ISO string or Unix timestamp
      checkOutTime: string | number | null;
      type: string;
    }>;

    const totalCheckIns = attendanceRecords.length;

    // Get recent check-ins (last 10)
    const recentCheckIns = attendanceRecords.slice(0, 10).map((record) => {
      let duration: number | undefined;

      // Convert Unix timestamps to milliseconds for calculation
      const checkInMs =
        typeof record.checkInTime === "number"
          ? record.checkInTime * 1000
          : new Date(record.checkInTime).getTime();

      if (record.checkOutTime) {
        const checkOutMs =
          typeof record.checkOutTime === "number"
            ? record.checkOutTime * 1000
            : new Date(record.checkOutTime).getTime();
        duration = Math.round((checkOutMs - checkInMs) / (1000 * 60)); // minutes
      }

      // Return with ISO string timestamps for consistency
      return {
        id: record.id,
        checkInTime: new Date(checkInMs).toISOString(),
        checkOutTime: record.checkOutTime
          ? new Date(
              typeof record.checkOutTime === "number"
                ? record.checkOutTime * 1000
                : record.checkOutTime,
            ).toISOString()
          : null,
        type: record.type,
        duration,
      };
    });

    // Calculate this week's check-ins
    const now = new Date();
    const startOfWeek = new Date(now);
    startOfWeek.setDate(now.getDate() - now.getDay()); // Sunday
    startOfWeek.setHours(0, 0, 0, 0);

    const thisWeekCheckIns = attendanceRecords.filter((r) => {
      // checkInTime is Unix timestamp in seconds, convert to milliseconds
      const checkInDate =
        typeof r.checkInTime === "number"
          ? new Date(r.checkInTime * 1000)
          : new Date(r.checkInTime);
      return checkInDate >= startOfWeek;
    }).length;

    // Calculate this month's check-ins
    const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
    const thisMonthCheckIns = attendanceRecords.filter((r) => {
      // checkInTime is Unix timestamp in seconds, convert to milliseconds
      const checkInDate =
        typeof r.checkInTime === "number"
          ? new Date(r.checkInTime * 1000)
          : new Date(r.checkInTime);
      return checkInDate >= startOfMonth;
    }).length;

    // Calculate current streak (consecutive days with check-ins)
    let currentStreak = 0;
    let longestStreak = 0;
    let tempStreak = 0;
    let lastDate: Date | null = null;

    const sortedRecords = [...attendanceRecords].sort((a, b) => {
      const dateA =
        typeof a.checkInTime === "number"
          ? new Date(a.checkInTime * 1000)
          : new Date(a.checkInTime);
      const dateB =
        typeof b.checkInTime === "number"
          ? new Date(b.checkInTime * 1000)
          : new Date(b.checkInTime);
      return dateB.getTime() - dateA.getTime();
    });

    const uniqueDays = new Set<string>();
    sortedRecords.forEach((record) => {
      const date =
        typeof record.checkInTime === "number"
          ? new Date(record.checkInTime * 1000)
          : new Date(record.checkInTime);
      const dateStr = date.toISOString().split("T")[0];
      uniqueDays.add(dateStr);
    });

    const sortedDays = Array.from(uniqueDays).sort().reverse();

    for (let i = 0; i < sortedDays.length; i++) {
      const currentDate = new Date(sortedDays[i]);

      if (lastDate === null) {
        tempStreak = 1;
        currentStreak = 1;
      } else {
        const dayDiff = Math.floor(
          (lastDate.getTime() - currentDate.getTime()) / (1000 * 60 * 60 * 24),
        );

        if (dayDiff === 1) {
          tempStreak++;
          if (i === 0 || currentStreak > 0) {
            currentStreak = tempStreak;
          }
        } else {
          if (currentStreak === 0) {
            currentStreak = 0;
          }
          tempStreak = 1;
        }
      }

      longestStreak = Math.max(longestStreak, tempStreak);
      lastDate = currentDate;
    }

    // Check if streak is still active (last check-in was today or yesterday)
    if (sortedDays.length > 0) {
      const lastCheckIn = new Date(sortedDays[0]);
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      const yesterday = new Date(today);
      yesterday.setDate(yesterday.getDate() - 1);

      lastCheckIn.setHours(0, 0, 0, 0);

      if (
        lastCheckIn.getTime() !== today.getTime() &&
        lastCheckIn.getTime() !== yesterday.getTime()
      ) {
        currentStreak = 0;
      }
    }

    const attendanceStats: AttendanceStats = {
      totalCheckIns,
      currentStreak,
      longestStreak,
      thisWeek: thisWeekCheckIns,
      thisMonth: thisMonthCheckIns,
      recentCheckIns,
    };

    // Calculate weekly trend (last 8 weeks)
    const weeklyTrend: WeeklyStats[] = [];
    for (let i = 7; i >= 0; i--) {
      const weekStart = new Date(now);
      weekStart.setDate(now.getDate() - now.getDay() - i * 7);
      weekStart.setHours(0, 0, 0, 0);

      const weekEnd = new Date(weekStart);
      weekEnd.setDate(weekStart.getDate() + 7);

      const weekCheckIns = attendanceRecords.filter((r) => {
        // checkInTime is Unix timestamp in seconds, convert to milliseconds
        const checkInDate =
          typeof r.checkInTime === "number"
            ? new Date(r.checkInTime * 1000)
            : new Date(r.checkInTime);
        return checkInDate >= weekStart && checkInDate < weekEnd;
      }).length;

      log.debug("Weekly calculation", {
        weekIndex: i,
        weekStart: weekStart.toISOString(),
        weekEnd: weekEnd.toISOString(),
        weekCheckIns,
        sampleRecord: attendanceRecords[0]
          ? {
              checkInTime: attendanceRecords[0].checkInTime,
              converted:
                typeof attendanceRecords[0].checkInTime === "number"
                  ? new Date(
                      attendanceRecords[0].checkInTime * 1000,
                    ).toISOString()
                  : attendanceRecords[0].checkInTime,
            }
          : null,
      });

      const weekGoalsCompleted = db
        .prepare(
          `SELECT COUNT(*) as count
           FROM fitness_goals
           WHERE user_id = ?
           AND status = 'completed'
           AND completed_date >= ?
           AND completed_date < ?`,
        )
        .get(userId, weekStart.toISOString(), weekEnd.toISOString()) as {
        count: number;
      };

      const weekActiveGoals = db
        .prepare(
          `SELECT progress
           FROM fitness_goals
           WHERE user_id = ?
           AND status = 'active'
           AND created_at < ?`,
        )
        .all(userId, weekEnd.toISOString()) as Array<{ progress: number }>;

      const weekAvgProgress =
        weekActiveGoals.length > 0
          ? weekActiveGoals.reduce((sum, g) => sum + (g.progress || 0), 0) /
            weekActiveGoals.length
          : 0;

      weeklyTrend.push({
        week: weekStart.toISOString().split("T")[0],
        checkIns: weekCheckIns,
        goalsCompleted: weekGoalsCompleted.count,
        avgProgress: Math.round(weekAvgProgress),
      });
    }

    const statistics: DashboardStatistics = {
      goals: goalStats,
      attendance: attendanceStats,
      weeklyTrend,
    };

    log.debug("Statistics calculated successfully", {
      userId,
      totalGoals: goalStats.total,
      totalCheckIns,
      weeklyTrendLength: weeklyTrend.length,
      weeklyTrendSample: weeklyTrend[0],
    });

    // Return statistics in standardized format that matches mobile app expectations
    return NextResponse.json({
      success: true,
      data: {
        statistics: {
          userId,
          goals: {
            totalGoals: goalStats.total,
            activeGoals: goalStats.active,
            completedGoals: goalStats.completed,
            averageProgress: goalStats.avgProgress,
            goalsByType: Object.entries(goalStats.byType).map(
              ([goalType, count]) => ({
                goalType,
                count,
              }),
            ),
          },
          attendance: {
            totalCheckIns: attendanceStats.totalCheckIns,
            currentStreak: attendanceStats.currentStreak,
            longestStreak: attendanceStats.longestStreak,
            checkInsThisWeek: attendanceStats.thisWeek,
            checkInsThisMonth: attendanceStats.thisMonth,
            recentCheckIns: attendanceStats.recentCheckIns,
          },
          weeklyTrend: weeklyTrend.map((week) => ({
            weekLabel: week.week,
            checkIns: week.checkIns,
            goalsCompleted: week.goalsCompleted,
            averageProgress: week.avgProgress,
          })),
        },
      },
      meta: {
        timestamp: new Date().toISOString(),
        requestId: `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
      },
    });
  } catch (error) {
    log.error("Failed to fetch statistics", error);
    return NextResponse.json(
      {
        success: false,
        error: { message: "Failed to fetch statistics" },
        meta: {
          timestamp: new Date().toISOString(),
          requestId: `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
        },
      },
      { status: 500 },
    );
  }
}
