import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import { authService } from '../services/auth.service.js';
import { authMiddleware } from '../middleware/auth.js';

const registerSchema = z.object({
  email: z.string().email('Invalid email format'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
  display_name: z.string().min(2, 'Display name must be at least 2 characters').max(50, 'Display name too long'),
});

const loginSchema = z.object({
  email: z.string().email('Invalid email format'),
  password: z.string().min(1, 'Password is required'),
});

const updateProfileSchema = z.object({
  display_name: z.string().min(2, 'Display name must be at least 2 characters').max(50, 'Display name too long').optional(),
  avatar_url: z.string().url('Invalid avatar URL').or(z.literal('')).optional(),
});

const changePasswordSchema = z.object({
  current_password: z.string().min(1, 'Current password is required'),
  new_password: z.string().min(8, 'New password must be at least 8 characters'),
});

const refreshTokenSchema = z.object({
  refresh_token: z.string().min(1, 'Refresh token is required'),
});

export async function authRoutes(app: FastifyInstance) {
  // POST /api/auth/register
  app.post('/api/auth/register', async (request, reply) => {
    try {
      const data = registerSchema.parse(request.body);
      
      const result = await authService.register(data.email, data.password, data.display_name);
      
      // Set refresh token as httpOnly cookie
      reply.setCookie('luna_refresh_token', result.tokens.refreshToken, {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'strict',
        maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
        path: '/',
      });
      
      reply.status(201).send({
        success: true,
        user: result.user,
        access_token: result.tokens.accessToken,
      });
    } catch (error: any) {
      if (error.message === 'EMAIL_EXISTS') {
        return reply.status(400).send({
          success: false,
          error: 'EMAIL_EXISTS',
          message: 'An account with this email already exists',
        });
      }
      
      if (error instanceof z.ZodError) {
        const firstError = error.errors && error.errors.length > 0 ? error.errors[0] : null;
        return reply.status(400).send({
          success: false,
          error: 'VALIDATION_ERROR',
          message: firstError?.message || 'Invalid data provided',
          details: error.errors,
        });
      }
      
      console.error('Register error:', error);
      reply.status(500).send({
        success: false,
        error: 'INTERNAL_ERROR',
        message: 'Registration failed',
      });
    }
  });

  // POST /api/auth/login
  app.post('/api/auth/login', async (request, reply) => {
    try {
      const data = loginSchema.parse(request.body);
      
      const result = await authService.login(data.email, data.password);
      
      // Set refresh token as httpOnly cookie
      reply.setCookie('luna_refresh_token', result.tokens.refreshToken, {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'strict',
        maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
        path: '/',
      });
      
      reply.send({
        success: true,
        user: result.user,
        access_token: result.tokens.accessToken,
      });
    } catch (error: any) {
      if (error.message === 'INVALID_CREDENTIALS') {
        return reply.status(401).send({
          success: false,
          error: 'INVALID_CREDENTIALS',
          message: 'Invalid email or password',
        });
      }
      
      if (error instanceof z.ZodError) {
        return reply.status(400).send({
          success: false,
          error: 'VALIDATION_ERROR',
          message: error.errors[0]?.message || 'Invalid data provided',
          details: error.errors,
        });
      }
      
      console.error('Login error:', error);
      reply.status(500).send({
        success: false,
        error: 'INTERNAL_ERROR',
        message: 'Login failed',
      });
    }
  });

  // POST /api/auth/logout
  app.post('/api/auth/logout', async (request, reply) => {
    // Clear refresh token cookie
    reply.clearCookie('luna_refresh_token', { path: '/' });
    
    reply.send({
      success: true,
      message: 'Successfully logged out',
    });
  });

  // GET /api/auth/me (protected)
  app.get('/api/auth/me', { preHandler: authMiddleware }, async (request, reply) => {
    try {
      const user = await authService.getProfile(request.user!.id);
      
      if (!user) {
        return reply.status(404).send({
          success: false,
          error: 'USER_NOT_FOUND',
          message: 'User not found',
        });
      }
      
      reply.send({
        success: true,
        user,
      });
    } catch (error) {
      console.error('Get profile error:', error);
      reply.status(500).send({
        success: false,
        error: 'INTERNAL_ERROR',
        message: 'Failed to get profile',
      });
    }
  });

  // PUT /api/auth/me (protected)
  app.put('/api/auth/me', { preHandler: authMiddleware }, async (request, reply) => {
    try {
      const data = updateProfileSchema.parse(request.body);
      
      const user = await authService.updateProfile(request.user!.id, data);
      
      reply.send({
        success: true,
        user,
      });
    } catch (error: any) {
      if (error.message === 'USER_NOT_FOUND') {
        return reply.status(404).send({
          success: false,
          error: 'USER_NOT_FOUND',
          message: 'User not found',
        });
      }
      
      if (error.message === 'NO_UPDATES_PROVIDED') {
        return reply.status(400).send({
          success: false,
          error: 'NO_UPDATES_PROVIDED',
          message: 'No updates provided',
        });
      }
      
      if (error instanceof z.ZodError) {
        return reply.status(400).send({
          success: false,
          error: 'VALIDATION_ERROR',
          message: error.errors[0]?.message || 'Invalid data provided',
          details: error.errors,
        });
      }
      
      console.error('Update profile error:', error);
      reply.status(500).send({
        success: false,
        error: 'INTERNAL_ERROR',
        message: 'Failed to update profile',
      });
    }
  });

  // PUT /api/auth/me/password (protected)
  app.put('/api/auth/me/password', { preHandler: authMiddleware }, async (request, reply) => {
    try {
      const data = changePasswordSchema.parse(request.body);
      
      await authService.changePassword(request.user!.id, data.current_password, data.new_password);
      
      reply.send({
        success: true,
        message: 'Password changed successfully',
      });
    } catch (error: any) {
      if (error.message === 'USER_NOT_FOUND') {
        return reply.status(404).send({
          success: false,
          error: 'USER_NOT_FOUND',
          message: 'User not found',
        });
      }
      
      if (error.message === 'INVALID_CURRENT_PASSWORD') {
        return reply.status(400).send({
          success: false,
          error: 'INVALID_CURRENT_PASSWORD',
          message: 'Current password is incorrect',
        });
      }
      
      if (error instanceof z.ZodError) {
        return reply.status(400).send({
          success: false,
          error: 'VALIDATION_ERROR',
          message: error.errors[0]?.message || 'Invalid data provided',
          details: error.errors,
        });
      }
      
      console.error('Change password error:', error);
      reply.status(500).send({
        success: false,
        error: 'INTERNAL_ERROR',
        message: 'Failed to change password',
      });
    }
  });

  // POST /api/auth/refresh (for refreshing access tokens)
  app.post('/api/auth/refresh', async (request, reply) => {
    try {
      const refreshToken = request.cookies.luna_refresh_token;
      
      if (!refreshToken) {
        return reply.status(401).send({
          success: false,
          error: 'MISSING_REFRESH_TOKEN',
          message: 'Refresh token required',
        });
      }
      
      const result = await authService.refreshTokens(refreshToken);
      
      // Set new refresh token as httpOnly cookie
      reply.setCookie('luna_refresh_token', result.tokens.refreshToken, {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'strict',
        maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
        path: '/',
      });
      
      reply.send({
        success: true,
        user: result.user,
        access_token: result.tokens.accessToken,
      });
    } catch (error: any) {
      if (error.message === 'INVALID_REFRESH_TOKEN' || error.message === 'USER_NOT_FOUND') {
        // Clear invalid refresh token cookie
        reply.clearCookie('luna_refresh_token', { path: '/' });
        
        return reply.status(401).send({
          success: false,
          error: 'INVALID_REFRESH_TOKEN',
          message: 'Invalid or expired refresh token',
        });
      }
      
      console.error('Refresh token error:', error);
      reply.status(500).send({
        success: false,
        error: 'INTERNAL_ERROR',
        message: 'Failed to refresh token',
      });
    }
  });
}
