import { FastifyInstance } from 'fastify';
import { prisma } from '../../../config/database';
import { optionalAuth } from '../middleware/auth';
import { logger } from '../../../utils/logger';

interface PaginationQuery {
  limit?: string;
  offset?: string;
  search?: string;
}

interface PlaylistParams {
  id: string;
}

interface ShareParams {
  token: string;
}

interface PlaylistIdQuery {
  shareToken?: string;
}

const playlistSelect = {
  id: true,
  name: true,
  description: true,
  isPublic: true,
  shareToken: true,
  videoCount: true,
  totalDurationSeconds: true,
  viewCount: true,
  createdAt: true,
  updatedAt: true,
  userId: true,
  user: {
    select: {
      id: true,
      name: true,
      email: true,
    },
  },
  featured: {
    select: {
      id: true,
      position: true,
    },
  },
  videos: {
    select: {
      media: {
        select: {
          thumbnailPath: true,
          id: true,
        },
      },
    },
    orderBy: { position: 'asc' as const },
    take: 1,
  },
};

function formatPlaylistSummary(playlist: any, requestUserId?: string) {
  const firstVideo = playlist.videos?.[0]?.media;
  return {
    id: playlist.id,
    name: playlist.name,
    description: playlist.description,
    isPublic: playlist.isPublic,
    shareToken: playlist.userId === requestUserId ? playlist.shareToken : undefined,
    videoCount: playlist.videoCount ?? 0,
    totalDurationSeconds: playlist.totalDurationSeconds ?? 0,
    viewCount: playlist.viewCount ?? 0,
    thumbnailUrl: firstVideo?.thumbnailPath
      ? `/media/videos/${firstVideo.id}/thumbnail`
      : null,
    createdAt: playlist.createdAt,
    updatedAt: playlist.updatedAt,
    creator: {
      id: playlist.user.id,
      name: playlist.user.name,
      email: playlist.user.email,
    },
    isFeatured: !!playlist.featured,
    featuredPosition: playlist.featured?.position ?? null,
    isOwner: playlist.userId === requestUserId,
  };
}

export async function playlistsPublicRoutes(fastify: FastifyInstance) {
  // GET /api/playlists/featured - Get featured playlists
  fastify.get<{ Querystring: PaginationQuery }>(
    '/featured',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const limit = Math.min(parseInt(request.query.limit || '12'), 50);
      const offset = parseInt(request.query.offset || '0');

      const featured = await prisma.featuredPlaylist.findMany({
        orderBy: { position: 'asc' },
        take: limit,
        skip: offset,
        include: {
          playlist: {
            select: playlistSelect,
          },
        },
      });

      const total = await prisma.featuredPlaylist.count();

      return {
        data: featured
          .filter((f) => f.playlist.isPublic)
          .map((f) => formatPlaylistSummary(f.playlist, request.user?.id)),
        total,
        limit,
        offset,
      };
    }
  );

  // GET /api/playlists/popular - Get popular public playlists
  fastify.get<{ Querystring: PaginationQuery }>(
    '/popular',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const limit = Math.min(parseInt(request.query.limit || '12'), 100);
      const offset = parseInt(request.query.offset || '0');
      const search = request.query.search;

      const where: any = { isPublic: true };
      if (search) {
        where.OR = [
          { name: { contains: search, mode: 'insensitive' } },
          { description: { contains: search, mode: 'insensitive' } },
        ];
      }

      const playlists = await prisma.playlist.findMany({
        where,
        select: playlistSelect,
        orderBy: { viewCount: 'desc' },
        take: limit,
        skip: offset,
      });

      const total = await prisma.playlist.count({ where });

      return {
        data: playlists.map((p) => formatPlaylistSummary(p, request.user?.id)),
        total,
        limit,
        offset,
      };
    }
  );

  // GET /api/playlists/share/:token - Get playlist by share token
  fastify.get<{ Params: ShareParams }>(
    '/share/:token',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const { token } = request.params;

      const playlist = await prisma.playlist.findUnique({
        where: { shareToken: token },
        select: {
          ...playlistSelect,
          videos: {
            select: {
              id: true,
              mediaId: true,
              position: true,
              addedAt: true,
              media: {
                select: {
                  id: true,
                  title: true,
                  filename: true,
                  durationSeconds: true,
                  quality: true,
                  orientation: true,
                  thumbnailPath: true,
                  viewCount: true,
                  isLocked: true,
                  isPublished: true,
                  createdAt: true,
                },
              },
            },
            orderBy: { position: 'asc' },
          },
        },
      });

      if (!playlist) {
        return reply.code(404).send({ message: 'Playlist not found' });
      }

      const summary = formatPlaylistSummary(playlist, request.user?.id);
      return {
        ...summary,
        videos: playlist.videos
          .filter((v) => v.media.isPublished)
          .map((v) => ({
            id: v.id,
            mediaId: v.mediaId,
            position: v.position,
            addedAt: v.addedAt,
            video: {
              id: v.media.id,
              title: v.media.title,
              filename: v.media.filename,
              durationSeconds: v.media.durationSeconds,
              quality: v.media.quality,
              orientation: v.media.orientation,
              thumbnailUrl: v.media.thumbnailPath
                ? `/media/videos/${v.media.id}/thumbnail`
                : null,
              viewCount: v.media.viewCount ?? 0,
              isLocked: v.media.isLocked ?? false,
              createdAt: v.media.createdAt,
            },
          })),
      };
    }
  );

  // GET /api/playlists/:id - Get playlist detail
  fastify.get<{ Params: PlaylistParams; Querystring: PlaylistIdQuery }>(
    '/:id',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const playlistId = parseInt(request.params.id);
      if (isNaN(playlistId)) {
        return reply.code(400).send({ message: 'Invalid playlist ID' });
      }

      const playlist = await prisma.playlist.findUnique({
        where: { id: playlistId },
        select: {
          ...playlistSelect,
          videos: {
            select: {
              id: true,
              mediaId: true,
              position: true,
              addedAt: true,
              media: {
                select: {
                  id: true,
                  title: true,
                  filename: true,
                  durationSeconds: true,
                  quality: true,
                  orientation: true,
                  thumbnailPath: true,
                  viewCount: true,
                  isLocked: true,
                  isPublished: true,
                  createdAt: true,
                },
              },
            },
            orderBy: { position: 'asc' },
          },
        },
      });

      if (!playlist) {
        return reply.code(404).send({ message: 'Playlist not found' });
      }

      // Access control: public, owner, or valid share token
      const isOwner = request.user?.id === playlist.userId;
      const isPublic = playlist.isPublic === true;
      const hasShareToken =
        request.query.shareToken && request.query.shareToken === playlist.shareToken;

      if (!isPublic && !isOwner && !hasShareToken) {
        return reply.code(404).send({ message: 'Playlist not found' });
      }

      const summary = formatPlaylistSummary(playlist, request.user?.id);
      return {
        ...summary,
        videos: playlist.videos
          .filter((v) => v.media.isPublished)
          .map((v) => ({
            id: v.id,
            mediaId: v.mediaId,
            position: v.position,
            addedAt: v.addedAt,
            video: {
              id: v.media.id,
              title: v.media.title,
              filename: v.media.filename,
              durationSeconds: v.media.durationSeconds,
              quality: v.media.quality,
              orientation: v.media.orientation,
              thumbnailUrl: v.media.thumbnailPath
                ? `/media/videos/${v.media.id}/thumbnail`
                : null,
              viewCount: v.media.viewCount ?? 0,
              isLocked: v.media.isLocked ?? false,
              createdAt: v.media.createdAt,
            },
          })),
      };
    }
  );

  // POST /api/playlists/:id/view - Record playlist view
  fastify.post<{ Params: PlaylistParams }>(
    '/:id/view',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const playlistId = parseInt(request.params.id);
      if (isNaN(playlistId)) {
        return reply.code(400).send({ message: 'Invalid playlist ID' });
      }

      const sessionId = request.headers['x-session-id'] as string;
      if (!sessionId) {
        return reply.code(400).send({ message: 'X-Session-ID header required' });
      }

      const playlist = await prisma.playlist.findUnique({
        where: { id: playlistId },
        select: { id: true },
      });

      if (!playlist) {
        return reply.code(404).send({ message: 'Playlist not found' });
      }

      try {
        // Ensure session exists
        await prisma.session.upsert({
          where: { id: sessionId },
          create: { id: sessionId },
          update: { lastSeenAt: new Date() },
        });

        // Check if already viewed recently (within 30 minutes)
        const recentView = await prisma.playlistView.findFirst({
          where: {
            playlistId,
            sessionId,
            createdAt: { gte: new Date(Date.now() - 30 * 60 * 1000) },
          },
        });

        if (!recentView) {
          await prisma.playlistView.create({
            data: { playlistId, sessionId },
          });

          await prisma.playlist.update({
            where: { id: playlistId },
            data: { viewCount: { increment: 1 } },
          });
        }

        return { success: true };
      } catch (error) {
        logger.error('Failed to record playlist view', { error, playlistId, sessionId });
        return { success: true }; // Don't fail the request for analytics errors
      }
    }
  );
}
