import { FastifyInstance } from 'fastify';
import { prisma } from '../../../config/database';
import { requireAdminRole } from '../middleware/auth';

/**
 * Photo album CRUD routes (prefix: /api/albums)
 */

interface CreateAlbumBody {
  title: string;
  description?: string;
  photoIds?: number[];
}

interface UpdateAlbumBody {
  title?: string;
  description?: string;
  category?: string;
  accessLevel?: string;
}

interface AddPhotosBody {
  photoIds: number[];
}

interface ReorderBody {
  photoIds: number[];
}

interface SetCoverBody {
  photoId: number;
}

export async function photoAlbumsRoutes(fastify: FastifyInstance) {
  // GET /api/albums - List albums
  fastify.get<{ Querystring: { limit?: string; offset?: string; search?: string } }>(
    '/',
    { preHandler: requireAdminRole },
    async (request) => {
      const limit = Math.min(parseInt(request.query.limit || '48'), 200);
      const offset = parseInt(request.query.offset || '0');
      const search = request.query.search;

      const where: any = {};
      if (search) {
        where.title = { contains: search, mode: 'insensitive' };
      }

      const [albums, total] = await Promise.all([
        prisma.photoAlbum.findMany({
          where,
          orderBy: { createdAt: 'desc' },
          take: limit,
          skip: offset,
          include: {
            coverPhoto: {
              select: { id: true, thumbnailPath: true },
            },
            creator: {
              select: { id: true, name: true, email: true },
            },
            _count: { select: { photos: true } },
          },
        }),
        prisma.photoAlbum.count({ where }),
      ]);

      return {
        albums: albums.map(a => ({
          ...a,
          photoCount: a._count.photos,
          coverThumbnailUrl: a.coverPhoto?.thumbnailPath
            ? `/media/photos/${a.coverPhoto.id}/thumbnail`
            : null,
        })),
        total,
        limit,
        offset,
      };
    }
  );

  // POST /api/albums - Create album
  fastify.post<{ Body: CreateAlbumBody }>(
    '/',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const { title, description, photoIds } = request.body;

      if (!title?.trim()) {
        return reply.code(400).send({ message: 'Title is required' });
      }

      const album = await prisma.photoAlbum.create({
        data: {
          title: title.trim(),
          description: description?.trim() || null,
          creatorId: request.user?.id || null,
          photoCount: photoIds?.length || 0,
        },
      });

      // Move photos into album if provided
      if (photoIds?.length) {
        for (let i = 0; i < photoIds.length; i++) {
          await prisma.photo.update({
            where: { id: photoIds[i] },
            data: { albumId: album.id, albumPosition: i },
          });
        }

        // Set first photo as cover
        await prisma.photoAlbum.update({
          where: { id: album.id },
          data: { coverPhotoId: photoIds[0] },
        });
      }

      return reply.code(201).send({ album });
    }
  );

  // GET /api/albums/:id - Album detail with photos
  fastify.get<{ Params: { id: string } }>(
    '/:id',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const id = parseInt(request.params.id as string);

      const album = await prisma.photoAlbum.findUnique({
        where: { id },
        include: {
          coverPhoto: { select: { id: true, thumbnailPath: true } },
          creator: { select: { id: true, name: true, email: true } },
          photos: {
            orderBy: { albumPosition: 'asc' },
            select: {
              id: true,
              title: true,
              originalFilename: true,
              thumbnailPath: true,
              width: true,
              height: true,
              orientation: true,
              format: true,
              fileSize: true,
              albumPosition: true,
              isPublished: true,
              createdAt: true,
            },
          },
        },
      });

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

      return {
        ...album,
        photos: album.photos.map(p => ({
          ...p,
          fileSize: p.fileSize?.toString() ?? null,
          thumbnailUrl: p.thumbnailPath ? `/media/photos/${p.id}/thumbnail` : null,
        })),
      };
    }
  );

  // PATCH /api/albums/:id - Update album metadata
  fastify.patch<{ Params: { id: string }; Body: UpdateAlbumBody }>(
    '/:id',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const id = parseInt(request.params.id as string);
      const { title, description, category, accessLevel } = request.body;

      const album = await prisma.photoAlbum.findUnique({ where: { id } });
      if (!album) {
        return reply.code(404).send({ message: 'Album not found' });
      }

      const updated = await prisma.photoAlbum.update({
        where: { id },
        data: {
          ...(title !== undefined && { title: title.trim() }),
          ...(description !== undefined && { description: description?.trim() || null }),
          ...(category !== undefined && { category }),
          ...(accessLevel !== undefined && { accessLevel }),
        },
      });

      return updated;
    }
  );

  // DELETE /api/albums/:id - Delete album (photos become orphaned, NOT deleted)
  fastify.delete<{ Params: { id: string } }>(
    '/:id',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const id = parseInt(request.params.id as string);

      const album = await prisma.photoAlbum.findUnique({ where: { id } });
      if (!album) {
        return reply.code(404).send({ message: 'Album not found' });
      }

      // Remove album reference from photos (orphan them)
      await prisma.photo.updateMany({
        where: { albumId: id },
        data: { albumId: null, albumPosition: null },
      });

      await prisma.photoAlbum.delete({ where: { id } });

      return { message: 'Album deleted, photos preserved' };
    }
  );

  // POST /api/albums/:id/photos - Add photos to album
  fastify.post<{ Params: { id: string }; Body: AddPhotosBody }>(
    '/:id/photos',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const albumId = parseInt(request.params.id as string);
      const { photoIds } = request.body;

      const album = await prisma.photoAlbum.findUnique({ where: { id: albumId } });
      if (!album) {
        return reply.code(404).send({ message: 'Album not found' });
      }

      // Find current max position
      const maxPos = await prisma.photo.aggregate({
        where: { albumId },
        _max: { albumPosition: true },
      });
      let nextPos = (maxPos._max.albumPosition ?? -1) + 1;

      for (const photoId of photoIds) {
        await prisma.photo.update({
          where: { id: photoId },
          data: { albumId, albumPosition: nextPos++ },
        });
      }

      // Update photo count
      const count = await prisma.photo.count({ where: { albumId } });
      await prisma.photoAlbum.update({
        where: { id: albumId },
        data: { photoCount: count },
      });

      // Set cover if album has none
      if (!album.coverPhotoId && photoIds.length > 0) {
        await prisma.photoAlbum.update({
          where: { id: albumId },
          data: { coverPhotoId: photoIds[0] },
        });
      }

      return { message: `Added ${photoIds.length} photos to album`, photoCount: count };
    }
  );

  // DELETE /api/albums/:id/photos/:photoId - Remove photo from album
  fastify.delete<{ Params: { id: string; photoId: string } }>(
    '/:id/photos/:photoId',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const albumId = parseInt(request.params.id as string);
      const photoId = parseInt(request.params.photoId as string);

      await prisma.photo.update({
        where: { id: photoId },
        data: { albumId: null, albumPosition: null },
      });

      // Clear cover if it was the removed photo
      const album = await prisma.photoAlbum.findUnique({ where: { id: albumId } });
      if (album?.coverPhotoId === photoId) {
        // Set next photo as cover or null
        const nextPhoto = await prisma.photo.findFirst({
          where: { albumId },
          orderBy: { albumPosition: 'asc' },
        });
        await prisma.photoAlbum.update({
          where: { id: albumId },
          data: { coverPhotoId: nextPhoto?.id ?? null },
        });
      }

      // Update count
      const count = await prisma.photo.count({ where: { albumId } });
      await prisma.photoAlbum.update({
        where: { id: albumId },
        data: { photoCount: count },
      });

      return { message: 'Photo removed from album', photoCount: count };
    }
  );

  // PUT /api/albums/:id/reorder - Reorder photos in album
  fastify.put<{ Params: { id: string }; Body: ReorderBody }>(
    '/:id/reorder',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const albumId = parseInt(request.params.id as string);
      const { photoIds } = request.body;

      // Update positions
      for (let i = 0; i < photoIds.length; i++) {
        await prisma.photo.update({
          where: { id: photoIds[i] },
          data: { albumPosition: i },
        });
      }

      return { message: 'Photos reordered' };
    }
  );

  // PUT /api/albums/:id/cover - Set cover photo
  fastify.put<{ Params: { id: string }; Body: SetCoverBody }>(
    '/:id/cover',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const albumId = parseInt(request.params.id as string);
      const { photoId } = request.body;

      await prisma.photoAlbum.update({
        where: { id: albumId },
        data: { coverPhotoId: photoId },
      });

      return { message: 'Cover photo set' };
    }
  );

  // POST /api/albums/:id/publish - Publish album + all its photos
  fastify.post<{ Params: { id: string } }>(
    '/:id/publish',
    { preHandler: requireAdminRole },
    async (request, reply) => {
      const albumId = parseInt(request.params.id as string);
      const now = new Date();

      await Promise.all([
        prisma.photoAlbum.update({
          where: { id: albumId },
          data: { isPublished: true, publishedAt: now },
        }),
        prisma.photo.updateMany({
          where: { albumId },
          data: { isPublished: true, publishedAt: now },
        }),
      ]);

      return { message: 'Album and photos published' };
    }
  );
}
