/**
 * BookDate: Record Swipe Action
 * Documentation: documentation/features/bookdate-prd.md
 */

import { NextRequest, NextResponse } from 'next/server';
import { requireAuth, AuthenticatedRequest } from '@/lib/middleware/auth';
import { prisma } from '@/lib/db';
import { getAudibleService } from '@/lib/integrations/audible.service';
import { getConfigService } from '@/lib/services/config.service';
import { RMABLogger } from '@/lib/utils/logger';
import { shouldSkipAutoSearch } from '@/lib/utils/release-date';

const logger = RMABLogger.create('API.BookDateSwipe');

async function handler(req: AuthenticatedRequest) {
  try {
    const userId = req.user!.id;
    const body = await req.json();
    const { recommendationId, action, markedAsKnown } = body;

    // Validation
    if (!recommendationId || !action) {
      return NextResponse.json(
        { error: 'recommendationId and action are required' },
        { status: 400 }
      );
    }

    if (!['left', 'right', 'up'].includes(action)) {
      return NextResponse.json(
        { error: 'Invalid action. Must be "left", "right", or "up"' },
        { status: 400 }
      );
    }

    // Get recommendation
    const recommendation = await prisma.bookDateRecommendation.findUnique({
      where: { id: recommendationId },
    });

    if (!recommendation || recommendation.userId !== userId) {
      return NextResponse.json(
        { error: 'Recommendation not found or does not belong to user' },
        { status: 404 }
      );
    }

    // Record swipe (keep recommendation in database for undo functionality)
    await prisma.bookDateSwipe.create({
      data: {
        userId,
        recommendationId,
        bookTitle: recommendation.title,
        bookAuthor: recommendation.author,
        action,
        markedAsKnown: markedAsKnown || false,
      },
    });

    // NOTE: We no longer delete the recommendation here.
    // This allows undo to work properly by keeping all the original data.
    // The recommendations endpoint filters out swiped cards.

    // If swiped right and not marked as known, create request
    if (action === 'right' && !markedAsKnown && recommendation.audnexusAsin) {
      try {
        // Fetch full details from Audnexus to get releaseDate, year, and series
        let year: number | undefined;
        let series: string | undefined;
        let seriesPart: string | undefined;
        let releaseDate: Date | null = null;
        try {
          const audibleService = getAudibleService();
          const audnexusData = await audibleService.getAudiobookDetails(recommendation.audnexusAsin);

          if (audnexusData?.releaseDate) {
            try {
              const parsed = new Date(audnexusData.releaseDate);
              if (!isNaN(parsed.getTime())) {
                releaseDate = parsed;
                const releaseYear = parsed.getFullYear();
                if (!isNaN(releaseYear)) {
                  year = releaseYear;
                  logger.debug(`Extracted year ${year} from Audnexus releaseDate: ${audnexusData.releaseDate}`);
                }
              }
            } catch (error) {
              logger.warn(`Failed to parse Audnexus releaseDate "${audnexusData.releaseDate}": ${error instanceof Error ? error.message : 'Unknown error'}`);
            }
          }

          // Extract series data
          if (audnexusData?.series) {
            series = audnexusData.series;
            logger.debug(`Extracted series: ${series}`);
          }
          if (audnexusData?.seriesPart) {
            seriesPart = audnexusData.seriesPart;
            logger.debug(`Extracted seriesPart: ${seriesPart}`);
          }
        } catch (error) {
          logger.warn(`Failed to fetch Audnexus data for ASIN ${recommendation.audnexusAsin}: ${error instanceof Error ? error.message : 'Unknown error'}`);
        }

        // Check if book already exists in audiobooks table
        let audiobook = await prisma.audiobook.findFirst({
          where: { audibleAsin: recommendation.audnexusAsin },
        });

        // If not, create it with year and series
        if (!audiobook) {
          audiobook = await prisma.audiobook.create({
            data: {
              audibleAsin: recommendation.audnexusAsin,
              title: recommendation.title,
              author: recommendation.author,
              narrator: recommendation.narrator,
              description: recommendation.description,
              coverArtUrl: recommendation.coverUrl,
              year,
              series,
              seriesPart,
              status: 'requested',
            },
          });
          logger.debug(`Created audiobook ${audiobook.id} with year: ${year || 'none'}, series: ${series || 'none'}`);
        } else if (year || series || seriesPart) {
          // Always update year/series if we have them from Audnexus (even if audiobook already has them)
          audiobook = await prisma.audiobook.update({
            where: { id: audiobook.id },
            data: {
              ...(year && { year }),
              ...(series && { series }),
              ...(seriesPart && { seriesPart }),
            },
          });
          logger.debug(`Updated audiobook ${audiobook.id} with year: ${year || 'unchanged'}, series: ${series || 'unchanged'}`);
        }

        // Create request (if not already exists)
        const existingRequest = await prisma.request.findFirst({
          where: {
            userId,
            audiobookId: audiobook.id,
            type: 'audiobook', // Only check audiobook requests (ebook requests are separate)
            deletedAt: null, // Only check active requests
          },
        });

        if (!existingRequest) {
          // Check if request needs approval (same logic as POST /api/requests)
          let needsApproval = false;

          // Fetch user with autoApproveRequests setting
          const user = await prisma.user.findUnique({
            where: { id: userId },
            select: {
              role: true,
              autoApproveRequests: true,
              plexUsername: true,
            },
          });

          if (!user) {
            logger.error('User not found during request creation');
            throw new Error('User not found');
          }

          // Determine if approval is needed
          if (user.role === 'admin') {
            // Admins always auto-approve
            needsApproval = false;
          } else {
            // Check user's personal setting first
            if (user.autoApproveRequests === true) {
              needsApproval = false;
            } else if (user.autoApproveRequests === false) {
              needsApproval = true;
            } else {
              // User setting is null, check global setting
              const globalConfig = await prisma.configuration.findUnique({
                where: { key: 'auto_approve_requests' },
              });
              // Default to true if not configured (backward compatibility)
              const globalAutoApprove = globalConfig === null ? true : globalConfig.value === 'true';
              needsApproval = !globalAutoApprove;
            }
          }

          // Evaluate release-date gate (only when not pending approval)
          let releaseGateSkip = false;
          if (!needsApproval) {
            try {
              const configService = getConfigService();
              const skipUnreleasedSetting = (await configService.get('indexer.skip_unreleased')) !== 'false';
              const gate = shouldSkipAutoSearch({ releaseDate }, skipUnreleasedSetting);
              releaseGateSkip = gate.skip;
            } catch (error) {
              logger.warn(`Failed to evaluate release-date gate: ${error instanceof Error ? error.message : 'Unknown error'}`);
            }
          }

          // Determine initial status
          let initialStatus: string;
          if (needsApproval) {
            initialStatus = 'awaiting_approval';
          } else if (releaseGateSkip) {
            initialStatus = 'awaiting_release';
          } else {
            initialStatus = 'pending';
          }

          const newRequest = await prisma.request.create({
            data: {
              userId,
              audiobookId: audiobook.id,
              status: initialStatus,
              type: 'audiobook', // Explicit type for user-created requests
              priority: 0,
              releaseDate,
            },
          });

          logger.info(`Created request for "${recommendation.title}" with status: ${initialStatus}`);

          if (releaseGateSkip) {
            logger.info(`Skipped auto-search for unreleased book`, {
              gateSource: 'BookDateSwipe',
              requestId: newRequest.id,
              audiobookTitle: audiobook.title,
              releaseDate: releaseDate?.toISOString() ?? null,
            });
          }

          // Import job queue service
          const { getJobQueueService } = await import('@/lib/services/job-queue.service');
          const jobQueue = getJobQueueService();

          // Send notification based on approval status
          if (needsApproval) {
            // Request needs approval - send pending notification
            await jobQueue.addNotificationJob(
              'request_pending_approval',
              newRequest.id,
              audiobook.title,
              audiobook.author,
              user.plexUsername || 'Unknown User'
            ).catch((error) => {
              logger.error('Failed to queue notification', { error: error instanceof Error ? error.message : String(error) });
            });
          } else {
            // Request was auto-approved - send approved notification
            await jobQueue.addNotificationJob(
              'request_approved',
              newRequest.id,
              audiobook.title,
              audiobook.author,
              user.plexUsername || 'Unknown User'
            ).catch((error) => {
              logger.error('Failed to queue notification', { error: error instanceof Error ? error.message : String(error) });
            });

            // Trigger search job only if auto-approved AND not gated by release date
            if (!releaseGateSkip) {
              await jobQueue.addSearchJob(newRequest.id, {
                id: audiobook.id,
                title: audiobook.title,
                author: audiobook.author,
                asin: audiobook.audibleAsin || undefined,
              });

              logger.info(`Triggered search job for request ${newRequest.id}`);
            }
          }
        }

      } catch (error) {
        logger.error('Error creating request', { error: error instanceof Error ? error.message : String(error) });
        // Don't fail the swipe if request creation fails
      }
    }

    return NextResponse.json({
      success: true,
      action,
      markedAsKnown,
    });

  } catch (error: any) {
    logger.error('Swipe error', { error: error instanceof Error ? error.message : String(error) });
    return NextResponse.json(
      { error: error.message || 'Failed to record swipe' },
      { status: 500 }
    );
  }
}

export async function POST(req: NextRequest) {
  return requireAuth(req, handler);
}
