import prisma from '../lib/prisma.js';

// Get all albums
export const getAllAlbums = async (req, res) => {
  try {
    const { status, search, sortBy = 'displayOrder', order = 'asc' } = req.query;

    const where = {};
    
    // Filter by status
    if (status && status !== 'all') {
      where.status = status;
    }

    // Search by title or artist
    if (search) {
      where.OR = [
        { title: { contains: search } },
        { artist: { contains: search } }
      ];
    }

    const albums = await prisma.album.findMany({
      where,
      orderBy: { [sortBy]: order }
    });

    // Parse genres JSON string to array
    const albumsWithParsedGenres = albums.map(album => ({
      ...album,
      genres: album.genres ? JSON.parse(album.genres) : []
    }));

    res.json(albumsWithParsedGenres);
  } catch (error) {
    console.error('Error fetching albums:', error);
    res.status(500).json({ error: 'Failed to fetch albums' });
  }
};

// Get single album by ID
export const getAlbumById = async (req, res) => {
  try {
    const { id } = req.params;
    
    const album = await prisma.album.findUnique({
      where: { id }
    });

    if (!album) {
      return res.status(404).json({ error: 'Album not found' });
    }

    // Parse genres JSON string to array
    const albumWithParsedGenres = {
      ...album,
      genres: album.genres ? JSON.parse(album.genres) : []
    };

    res.json(albumWithParsedGenres);
  } catch (error) {
    console.error('Error fetching album:', error);
    res.status(500).json({ error: 'Failed to fetch album' });
  }
};

// Create new album
export const createAlbum = async (req, res) => {
  try {
    const { 
      title, 
      artist, 
      article, 
      imageUrl, 
      spotifyLink, 
      genres, 
      releaseDate, 
      status, 
      displayOrder 
    } = req.body;

    // Validation
    if (!title || !artist) {
      return res.status(400).json({ error: 'Title and artist are required' });
    }

    // Convert genres array to JSON string
    const genresString = JSON.stringify(genres || []);

    const album = await prisma.album.create({
      data: {
        title,
        artist,
        article,
        imageUrl,
        spotifyLink,
        genres: genresString,
        releaseDate: releaseDate ? new Date(releaseDate) : null,
        status: status || 'published',
        displayOrder: displayOrder || 0
      }
    });

    // Return with parsed genres
    res.status(201).json({
      ...album,
      genres: JSON.parse(album.genres)
    });
  } catch (error) {
    console.error('Error creating album:', error);
    res.status(500).json({ error: 'Failed to create album' });
  }
};

// Update album
export const updateAlbum = async (req, res) => {
  try {
    const { id } = req.params;
    const { 
      title, 
      artist, 
      article, 
      imageUrl, 
      spotifyLink, 
      genres, 
      releaseDate, 
      status, 
      displayOrder 
    } = req.body;

    // Check if album exists
    const existingAlbum = await prisma.album.findUnique({
      where: { id }
    });

    if (!existingAlbum) {
      return res.status(404).json({ error: 'Album not found' });
    }

    // If displayOrder is being updated, handle the swap logic
    if (displayOrder !== undefined && displayOrder !== existingAlbum.displayOrder) {
      // Get all albums to find if another album has the target display order
      const allAlbums = await prisma.album.findMany({
        orderBy: { displayOrder: 'asc' }
      });

      const totalAlbums = allAlbums.length;

      // Validate new order is within bounds
      if (displayOrder < 1 || displayOrder > totalAlbums) {
        return res.status(400).json({ 
          error: `Display order must be between 1 and ${totalAlbums}` 
        });
      }

      // Find the album that currently has the target display order
      const albumAtTargetOrder = allAlbums.find(album => 
        album.displayOrder === displayOrder && album.id !== id
      );

      // Prepare updates for the swap
      const updates = [];

      if (albumAtTargetOrder) {
        // Swap the two albums
        updates.push(
          {
            id: id,
            displayOrder: displayOrder
          },
          {
            id: albumAtTargetOrder.id,
            displayOrder: existingAlbum.displayOrder
          }
        );
      } else {
        // If no album at target order, just update the current album
        updates.push({
          id: id,
          displayOrder: displayOrder
        });
      }

      // Prepare other update data (excluding displayOrder since it's handled above)
      const otherUpdateData = {};
      if (title !== undefined) otherUpdateData.title = title;
      if (artist !== undefined) otherUpdateData.artist = artist;
      if (article !== undefined) otherUpdateData.article = article;
      if (imageUrl !== undefined) otherUpdateData.imageUrl = imageUrl;
      if (spotifyLink !== undefined) otherUpdateData.spotifyLink = spotifyLink;
      if (genres !== undefined) otherUpdateData.genres = JSON.stringify(genres);
      if (releaseDate !== undefined) otherUpdateData.releaseDate = releaseDate ? new Date(releaseDate) : null;
      if (status !== undefined) otherUpdateData.status = status;

      // Add other updates to the main album update
      if (Object.keys(otherUpdateData).length > 0) {
        updates[0] = { ...updates[0], ...otherUpdateData };
      }

      // Update albums in a transaction
      const updatePromises = updates.map(({ id: albumId, displayOrder: newDisplayOrder, ...otherData }) =>
        prisma.album.update({
          where: { id: albumId },
          data: { 
            displayOrder: newDisplayOrder,
            ...otherData
          }
        })
      );

      await prisma.$transaction(updatePromises);

      // Get the updated album
      const album = await prisma.album.findUnique({
        where: { id }
      });

      // Return with parsed genres
      res.json({
        ...album,
        genres: JSON.parse(album.genres),
        swappedWith: albumAtTargetOrder ? albumAtTargetOrder.id : null
      });
    } else {
      // No display order change, proceed with normal update
      const updateData = {};
      if (title !== undefined) updateData.title = title;
      if (artist !== undefined) updateData.artist = artist;
      if (article !== undefined) updateData.article = article;
      if (imageUrl !== undefined) updateData.imageUrl = imageUrl;
      if (spotifyLink !== undefined) updateData.spotifyLink = spotifyLink;
      if (genres !== undefined) updateData.genres = JSON.stringify(genres);
      if (releaseDate !== undefined) updateData.releaseDate = releaseDate ? new Date(releaseDate) : null;
      if (status !== undefined) updateData.status = status;
      if (displayOrder !== undefined) updateData.displayOrder = displayOrder;

      const album = await prisma.album.update({
        where: { id },
        data: updateData
      });

      // Return with parsed genres
      res.json({
        ...album,
        genres: JSON.parse(album.genres)
      });
    }
  } catch (error) {
    console.error('Error updating album:', error);
    res.status(500).json({ error: 'Failed to update album' });
  }
};

// Delete album
export const deleteAlbum = async (req, res) => {
  try {
    const { id } = req.params;

    // Check if album exists
    const existingAlbum = await prisma.album.findUnique({
      where: { id }
    });

    if (!existingAlbum) {
      return res.status(404).json({ error: 'Album not found' });
    }

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

    res.json({ message: 'Album deleted successfully' });
  } catch (error) {
    console.error('Error deleting album:', error);
    res.status(500).json({ error: 'Failed to delete album' });
  }
};

// Reorder albums - smart swapping logic
export const reorderAlbums = async (req, res) => {
  try {
    const { id: albumId } = req.params;
    const { newOrder } = req.body;

    if (!albumId || newOrder === undefined) {
      return res.status(400).json({ error: 'Album ID and new order are required' });
    }

    // Get the album being moved
    const albumToMove = await prisma.album.findUnique({
      where: { id: albumId }
    });

    if (!albumToMove) {
      return res.status(404).json({ error: 'Album not found' });
    }

    const currentOrder = albumToMove.displayOrder;

    // Get all albums to understand the current state
    const allAlbums = await prisma.album.findMany({
      orderBy: { displayOrder: 'asc' }
    });

    const totalAlbums = allAlbums.length;

    // Validate new order is within bounds
    if (newOrder < 1 || newOrder > totalAlbums) {
      return res.status(400).json({ 
        error: `Order must be between 1 and ${totalAlbums}` 
      });
    }

    // If the order hasn't changed, no need to do anything
    if (currentOrder === newOrder) {
      return res.json({ message: 'No changes needed' });
    }

    // Create the new order array
    const newOrderArray = allAlbums.map(album => ({ ...album, displayOrder: album.displayOrder }));

    // Remove the album being moved from its current position
    const albumIndex = newOrderArray.findIndex(album => album.id === albumId);
    const [movedAlbum] = newOrderArray.splice(albumIndex, 1);

    // Insert the album at its new position
    newOrderArray.splice(newOrder - 1, 0, movedAlbum);

    // Reassign orders sequentially
    const updates = newOrderArray.map((album, index) => ({
      id: album.id,
      displayOrder: index + 1
    }));

    // Update all albums in a transaction
    const updatePromises = updates.map(({ id, displayOrder }) =>
      prisma.album.update({
        where: { id },
        data: { displayOrder }
      })
    );

    await prisma.$transaction(updatePromises);

    res.json({ 
      message: 'Albums reordered successfully',
      newOrder: newOrder,
      totalAlbums: totalAlbums
    });
  } catch (error) {
    console.error('Error reordering albums:', error);
    res.status(500).json({ error: 'Failed to reorder albums' });
  }
};
