/**
 * Component: User Password Change API
 * Documentation: documentation/backend/services/auth.md
 */

import { NextRequest, NextResponse } from 'next/server';
import { requireAuth, AuthenticatedRequest } from '@/lib/middleware/auth';
import { prisma } from '@/lib/db';
import bcrypt from 'bcrypt';
import { getEncryptionService } from '@/lib/services/encryption.service';
import { RMABLogger } from '@/lib/utils/logger';

const logger = RMABLogger.create('API.Auth.ChangePassword');

/**
 * POST /api/auth/change-password
 * Change password for any authenticated local user
 *
 * Security:
 * - Only available to local users (authProvider='local')
 * - Requires current password verification
 * - New password must be at least 8 characters
 * - New password must be different from current password
 */
export async function POST(request: NextRequest) {
  return requireAuth(request, async (req: AuthenticatedRequest) => {
    try {
      const { currentPassword, newPassword, confirmPassword } = await request.json();

      // Validate input
      if (!currentPassword || !newPassword || !confirmPassword) {
        return NextResponse.json(
          {
            success: false,
            error: 'All fields are required',
          },
          { status: 400 }
        );
      }

      // Validate new password length
      const allowWeakPassword = process.env.ALLOW_WEAK_PASSWORD === 'true';
      if (!allowWeakPassword && newPassword.length < 8) {
        return NextResponse.json(
          {
            success: false,
            error: 'New password must be at least 8 characters',
          },
          { status: 400 }
        );
      }

      // Validate passwords match
      if (newPassword !== confirmPassword) {
        return NextResponse.json(
          {
            success: false,
            error: 'New passwords do not match',
          },
          { status: 400 }
        );
      }

      // Validate new password is different from current
      if (currentPassword === newPassword) {
        return NextResponse.json(
          {
            success: false,
            error: 'New password must be different from current password',
          },
          { status: 400 }
        );
      }

      // Get user from database
      const user = await prisma.user.findUnique({
        where: { id: req.user!.id },
        select: {
          id: true,
          authToken: true,
          authProvider: true,
          plexId: true,
          plexUsername: true,
        },
      });

      if (!user) {
        return NextResponse.json(
          {
            success: false,
            error: 'User not found',
          },
          { status: 404 }
        );
      }

      // Check if user is a local user (can change password)
      if (user.authProvider !== 'local') {
        return NextResponse.json(
          {
            success: false,
            error: 'Password change is only available for local users. Your account is managed by an external provider.',
          },
          { status: 403 }
        );
      }

      if (!user.authToken) {
        return NextResponse.json(
          {
            success: false,
            error: 'Invalid account configuration',
          },
          { status: 400 }
        );
      }

      // Decrypt the stored hash before comparing
      const encryptionService = getEncryptionService();
      let decryptedHash: string;
      try {
        decryptedHash = encryptionService.decrypt(user.authToken);
      } catch (error) {
        logger.error('Failed to decrypt password hash', {
          userId: user.id,
          error: error instanceof Error ? error.message : String(error)
        });
        return NextResponse.json(
          {
            success: false,
            error: 'Failed to verify current password',
          },
          { status: 500 }
        );
      }

      // Verify current password
      const currentPasswordValid = await bcrypt.compare(currentPassword, decryptedHash);

      if (!currentPasswordValid) {
        return NextResponse.json(
          {
            success: false,
            error: 'Current password is incorrect',
          },
          { status: 400 }
        );
      }

      // Hash new password
      const hashedPassword = await bcrypt.hash(newPassword, 10);

      // Encrypt the new hash before storing
      const encryptedHash = encryptionService.encrypt(hashedPassword);

      // Update password in database
      await prisma.user.update({
        where: { id: user.id },
        data: {
          authToken: encryptedHash,
          updatedAt: new Date(),
        },
      });

      logger.info('Password changed successfully', {
        userId: user.id,
        username: user.plexUsername
      });

      return NextResponse.json({
        success: true,
        message: 'Password changed successfully',
      });
    } catch (error) {
      logger.error('Failed to change password', {
        error: error instanceof Error ? error.message : String(error)
      });
      return NextResponse.json(
        {
          success: false,
          error: error instanceof Error ? error.message : 'Failed to change password',
        },
        { status: 500 }
      );
    }
  });
}
