// app/api/progress/route.ts
import { NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth-options';
import { prisma } from '@/lib/prisma';

export async function GET(req: Request) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user?.email)
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

    const userEmail = session.user.email;
    const { searchParams } = new URL(req.url);
    const videoId = searchParams.get('videoId');

    if (!videoId)
      return NextResponse.json({ error: 'videoId required' }, { status: 400 });

    const user = await prisma.user.findUnique({ where: { email: userEmail } });
    if (!user)
      return NextResponse.json({ error: 'user not found' }, { status: 404 });

    // Validate that the video exists
    const video = await prisma.video.findUnique({ where: { id: videoId } });
    if (!video) {
      console.debug(`[PROGRESS] Video not found: ${videoId} (likely deleted video with cached browser reference)`);
      return NextResponse.json({ error: 'video not found' }, { status: 404 });
    }

    const progress = await prisma.videoProgress.findUnique({
      where: { userId_videoId: { userId: user.id, videoId } },
      select: { percent: true, lastPos: true, watchedSec: true },
    });

    return NextResponse.json({ 
      percent: progress?.percent ?? 0,
      lastPos: progress?.lastPos ?? 0,
      watchedSec: progress?.watchedSec ?? 0,
    });
  } catch (err: any) {
    console.error('progress GET error', err);
    return NextResponse.json(
      { error: err?.message ?? 'server error' },
      { status: 500 }
    );
  }
}

// Helper function to calculate unique watched seconds from segments
function calculateWatchedSeconds(segments: Array<{ startSec: number; endSec: number }>): number {
  if (segments.length === 0) return 0;
  
  // Sort and merge overlapping ranges
  const sorted = segments.sort((a, b) => a.startSec - b.startSec);
  const merged: Array<[number, number]> = [];
  
  for (const seg of sorted) {
    if (merged.length === 0) {
      merged.push([seg.startSec, seg.endSec]);
    } else {
      const last = merged[merged.length - 1];
      if (seg.startSec <= last[1] + 0.5) {
        // Overlapping or adjacent, merge
        last[1] = Math.max(last[1], seg.endSec);
      } else {
        // Gap, new range
        merged.push([seg.startSec, seg.endSec]);
      }
    }
  }
  
  let total = 0;
  for (const [start, end] of merged) {
    total += Math.max(0, end - start);
  }
  return Math.round(total);
}

export async function POST(req: Request) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user?.email)
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });

    const userEmail = session.user.email;

    const body = await req.json().catch(() => ({}));
    const { videoId, playlistId, watchedSec, lastPos, duration } = body ?? {};

    if (!videoId)
      return NextResponse.json({ error: 'videoId required' }, { status: 400 });
    if (!duration || Number(duration) <= 0)
      return NextResponse.json({ error: 'duration required' }, { status: 400 });

    const watched = Number(watchedSec ?? 0);
    const lastPosition = Number(lastPos ?? 0);
    const dur = Number(duration);

    // look up user id
    const user = await prisma.user.findUnique({ where: { email: userEmail } });
    if (!user)
      return NextResponse.json({ error: 'user not found' }, { status: 404 });

    // Validate that the video exists
    const video = await prisma.video.findUnique({ where: { id: videoId } });
    if (!video) {
      // Log at debug level since this is expected when users have old cached references
      console.debug(`[PROGRESS] Video not found: ${videoId} (likely deleted video with cached browser reference)`);
      return NextResponse.json({ error: 'video not found' }, { status: 404 });
    }

    // Ensure VideoProgress exists or create it
    let videoProgress = await prisma.videoProgress.findUnique({
      where: { userId_videoId: { userId: user.id, videoId } },
    });

    if (!videoProgress) {
      videoProgress = await prisma.videoProgress.create({
        data: {
          userId: user.id,
          videoId,
          watchedSec: 0,
          lastPos: 0,
          percent: 0,
          durationSec: dur,
        },
      });
    }

    // Record the watch segment if watched seconds > 0
    let newSegment = null;
    if (watched > 0) {
      newSegment = await prisma.videoWatchSegment.create({
        data: {
          userId: user.id,
          videoId,
          startSec: Math.max(0, lastPosition - watched),
          endSec: lastPosition,
        },
      });
    }

    // Fetch all segments for this user+video to recalculate totals
    const allSegments = await prisma.videoWatchSegment.findMany({
      where: { userId: user.id, videoId },
      select: { startSec: true, endSec: true },
      orderBy: { createdAt: 'asc' },
    });

    // Calculate total unique watched seconds
    const totalWatchedSec = calculateWatchedSeconds(allSegments);

    // Calculate completion percentage
    const ratio = dur > 0 ? totalWatchedSec / dur : 0;
    const percentInt = Math.min(100, Math.round(ratio * 100));
    const completed = percentInt >= 80; // Changed from 90 to 80 for unlock threshold

    // Update VideoProgress with recalculated values
    const upserted = await prisma.videoProgress.update({
      where: { userId_videoId: { userId: user.id, videoId } },
      data: {
        watchedSec: totalWatchedSec,
        lastPos: Math.max(videoProgress.lastPos ?? 0, lastPosition),
        percent: percentInt,
        durationSec: dur,
        completed,
        updatedAt: new Date(),
      },
    });

    // If 80% watched, unlock next video in playlist for this user
    let unlockedNext = null;
    if (completed && playlistId) {
      // find current video
      const current = await prisma.video.findUnique({ where: { id: videoId } });
      if (current && current.playlistId === playlistId) {
        // Find next video that is NOT instant access and NOT globally locked
        // Skip any instant access videos in the sequence
        const nextVideos = await prisma.video.findMany({
          where: {
            playlistId,
            index: { gt: current.index },
            locked: false,
            instantAccess: false,
          },
          orderBy: { index: 'asc' },
          take: 1,
        });

        if (nextVideos.length > 0) {
          const next = nextVideos[0];
          // Create a VideoUnlock record for this user (per-user unlock tracking)
          const unlock = await prisma.videoUnlock.upsert({
            where: { userId_videoId: { userId: user.id, videoId: next.id } },
            update: {}, // if already exists, do nothing
            create: { userId: user.id, videoId: next.id },
          });
          unlockedNext = { id: next.id, title: next.title };
        }
      }
    }

    return NextResponse.json({ ok: true, progress: upserted, unlockedNext, segment: newSegment });
  } catch (err: any) {
    console.error('progress error', err);
    
    // Handle foreign key constraint violations
    if (err.code === 'P2003') {
      const constraint = err.meta?.constraint_name;
      if (constraint?.includes('videoId')) {
        console.error(`[PROGRESS] Foreign key violation - invalid videoId: ${err.meta}`);
        return NextResponse.json(
          { error: 'Invalid video reference' },
          { status: 400 }
        );
      }
    }
    
    return NextResponse.json(
      { error: err?.message ?? 'server error' },
      { status: 500 }
    );
  }
}
