/**
 * Component: Plex Profile Switch API
 * Documentation: documentation/backend/services/auth.md
 */

import { NextRequest, NextResponse } from 'next/server';
import { getPlexService } from '@/lib/integrations/plex.service';
import { getEncryptionService } from '@/lib/services/encryption.service';
import { getAuthTokenCache } from '@/lib/services/auth-token-cache.service';
import { generateAccessToken, generateRefreshToken } from '@/lib/utils/jwt';
import { prisma } from '@/lib/db';
import { RMABLogger } from '@/lib/utils/logger';

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

/**
 * POST /api/auth/plex/switch-profile
 * Switch to a Plex Home profile and complete authentication
 *
 * Authentication: Provide pinId in request body. The Plex token is
 * retrieved from server-side cache for security.
 */
export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const { userId, pin, pinId, profileInfo } = body;

    // Validate pinId is provided
    if (!pinId) {
      logger.warn('Missing pinId in request body');
      return NextResponse.json(
        {
          error: 'Unauthorized',
          message: 'Missing PIN ID. Please restart the login process.',
        },
        { status: 401 }
      );
    }

    // Retrieve the Plex token from server-side cache
    const tokenCache = getAuthTokenCache();
    const mainAccountToken = tokenCache.get(pinId);

    if (!mainAccountToken) {
      logger.warn('Token not found or expired for pinId', { pinId });
      return NextResponse.json(
        {
          error: 'SessionExpired',
          message: 'Your session has expired. Please restart the login process.',
        },
        { status: 401 }
      );
    }

    if (!userId) {
      return NextResponse.json(
        {
          error: 'ValidationError',
          message: 'Missing userId',
        },
        { status: 400 }
      );
    }

    const plexService = getPlexService();
    const encryptionService = getEncryptionService();

    // Switch to selected profile
    let profileToken: string;
    try {
      const token = await plexService.switchHomeUser(userId, mainAccountToken, pin);
      if (!token) {
        throw new Error('Failed to get profile token');
      }
      profileToken = token;
    } catch (error: any) {
      if (error.message === 'Invalid PIN') {
        return NextResponse.json(
          {
            error: 'InvalidPIN',
            message: 'Invalid PIN for this profile',
          },
          { status: 401 }
        );
      }
      throw error;
    }

    // Use profile info from request (already has all the info from home users list)
    // or fall back to getUserInfo for main accounts
    let profilePlexId: string;
    let profileUsername: string;
    let profileEmail: string | null;
    let profileThumb: string | null;

    if (profileInfo && profileInfo.uuid) {
      // Use provided profile info (from home users list - more reliable for managed users)
      profilePlexId = profileInfo.uuid;
      profileUsername = profileInfo.friendlyName || `User ${userId}`;
      profileEmail = profileInfo.email || null;
      profileThumb = profileInfo.thumb || null;
      logger.debug('Using provided profile info', {
        plexId: profilePlexId,
        username: profileUsername,
      });
    } else {
      // Fall back to getUserInfo (for main accounts without profile info)
      const profileUser = await plexService.getUserInfo(profileToken);

      if (!profileUser || !profileUser.id) {
        logger.error('Failed to get profile user info');
        return NextResponse.json(
          {
            error: 'ServerError',
            message: 'Failed to get profile information',
          },
          { status: 500 }
        );
      }

      profilePlexId = typeof profileUser.id === 'string' ? profileUser.id : profileUser.id.toString();
      profileUsername = profileUser.username || `User ${userId}`;
      profileEmail = profileUser.email || null;
      profileThumb = profileUser.thumb || null;
      logger.debug('Using getUserInfo data', {
        plexId: profilePlexId,
        username: profileUsername,
      });
    }

    // Check if this is the first user (should be promoted to admin)
    const userCount = await prisma.user.count();
    const isFirstUser = userCount === 0;
    const role = isFirstUser ? 'admin' : 'user';

    // Create or update user with profile details
    const user = await prisma.user.upsert({
      where: { plexId: profilePlexId },
      create: {
        plexId: profilePlexId,
        plexUsername: profileUsername,
        plexEmail: profileEmail,
        role,
        avatarUrl: profileThumb,
        authToken: encryptionService.encrypt(profileToken),
        plexHomeUserId: userId, // Store the home user ID
        lastLoginAt: new Date(),
      },
      update: {
        plexUsername: profileUsername,
        plexEmail: profileEmail,
        avatarUrl: profileThumb,
        authToken: encryptionService.encrypt(profileToken),
        plexHomeUserId: userId, // Update the home user ID
        lastLoginAt: new Date(),
      },
    });

    logger.info('User authenticated', {
      id: user.id,
      plexId: user.plexId,
      username: user.plexUsername,
      homeUserId: user.plexHomeUserId,
      role: user.role,
    });

    // Generate JWT tokens
    const accessToken = generateAccessToken({
      sub: user.id,
      plexId: user.plexId,
      username: user.plexUsername,
      role: user.role,
    });

    const refreshToken = generateRefreshToken(user.id);

    // Clean up the cached Plex token - authentication is complete
    tokenCache.delete(pinId);
    logger.debug('Cached Plex token cleaned up after successful auth', { pinId });

    // Return tokens and user info
    return NextResponse.json({
      success: true,
      accessToken,
      refreshToken,
      user: {
        id: user.id,
        plexId: user.plexId,
        username: user.plexUsername,
        email: user.plexEmail,
        role: user.role,
        avatarUrl: user.avatarUrl,
      },
    });
  } catch (error) {
    logger.error('Failed to switch profile', { error: error instanceof Error ? error.message : String(error) });
    return NextResponse.json(
      {
        error: 'ServerError',
        message: 'Failed to switch to selected profile',
        details: error instanceof Error ? error.message : 'Unknown error',
      },
      { status: 500 }
    );
  }
}
