import { Body, Post, Route, Tags, SuccessResponse, Response, Example, Controller, Security, Request } from 'tsoa';
import { AuthService } from '../services/auth.service';
import {
    LoginRequest,
    RegisterRequest,
    RefreshTokenRequest,
    ResetRequest,
    ResetPasswordRequest,
    LoginResponse,
    RegisterResponse,
    RefreshTokenResponse
} from '../types/auth.types';
import { loginSchema, registerSchema, refreshTokenSchema, resetRequestSchema, resetPasswordSchema } from '../validators/auth.validator';
import { ValidationError } from '../middleware/errorHandler';

@Route('api/auth')
@Tags('Authentication')
export class AuthController {
    private authService = new AuthService();

    /**
     * User login
     * @summary Login with email and password
     * @param body Login credentials
     * @returns JWT token and user information
     */
    @Post('login')
    @SuccessResponse('200', 'Login successful')
    @Response('401', 'Invalid credentials')
    @Example<LoginResponse>({
        code: 200,
        message: 'Login successful',
        data: {
            token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
            refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
            user: {
                id: 1,
                username: 'admin',
                email: 'admin@elearning.local',
                email_verified_at: new Date('2024-01-01T00:00:00Z'),
                updated_at: new Date('2024-01-01T00:00:00Z'),
                created_at: new Date('2024-01-01T00:00:00Z'),
                role: {
                    code: 'ADMIN',
                    name: {
                        th: 'ผู้ดูแลระบบ',
                        en: 'Administrator'
                    }
                },
                profile: {
                    prefix: {
                        th: 'นาย',
                        en: 'Mr.'
                    },
                    first_name: 'Admin',
                    last_name: 'User',
                    phone: null,
                    avatar_url: null,
                    birth_date: null
                }
            }
        }
    })
    public async login(@Body() body: LoginRequest): Promise<LoginResponse> {
        // Validate input
        const { error, value } = loginSchema.validate(body);

        if (error) {
            throw new ValidationError(error.details[0].message);
        }

        return await this.authService.login(body);
    }

    /**
     * User registration
     * @summary Register a new instructor account
     * @param body Registration data
     * @returns Created user information
     */
    @Post('register-instructor')
    @SuccessResponse('201', 'Registration successful')
    @Response('400', 'Validation error')
    @Response('409', 'Username or email already exists')
    @Example<RegisterResponse>({
        user: {
            id: 4,
            username: 'newinstructor',
            email: 'instructor@example.com',
            email_verified_at: null,
            updated_at: new Date('2024-01-01T00:00:00Z'),
            created_at: new Date('2024-01-01T00:00:00Z'),
            role: {
                code: 'INSTRUCTOR',
                name: {
                    th: 'ผู้สอน',
                    en: 'Instructor'
                }
            },
            profile: {
                prefix: {
                    th: 'นาย',
                    en: 'Mr.'
                },
                first_name: 'John',
                last_name: 'Doe',
                phone: null,
                avatar_url: null,
                birth_date: null
            }
        },
        message: 'Registration successful'
    })
    public async registerInstructor(@Body() body: RegisterRequest): Promise<RegisterResponse> {
        // Validate input
        const { error } = registerSchema.validate(body);
        if (error) {
            throw new ValidationError(error.details[0].message);
        }

        return await this.authService.registerInstructor(body);
    }

    /**
     * User registration
     * @summary Register a new student account
     * @param body Registration data
     * @returns Created user information
     */
    @Post('register-learner')
    @SuccessResponse('201', 'Registration successful')
    @Response('400', 'Validation error')
    @Response('409', 'Username or email already exists')
    @Example<RegisterResponse>({
        user: {
            id: 4,
            username: 'newstudent',
            email: 'student@example.com',
            email_verified_at: null,
            updated_at: new Date('2024-01-01T00:00:00Z'),
            created_at: new Date('2024-01-01T00:00:00Z'),
            role: {
                code: 'STUDENT',
                name: {
                    th: 'นักเรียน',
                    en: 'Student'
                }
            },
            profile: {
                prefix: {
                    th: 'นาย',
                    en: 'Mr.'
                },
                first_name: 'John',
                last_name: 'Doe',
                phone: null,
                avatar_url: null,
                birth_date: null
            }
        },
        message: 'Registration successful'
    })
    public async register(@Body() body: RegisterRequest): Promise<RegisterResponse> {
        // Validate input
        const { error } = registerSchema.validate(body);
        if (error) {
            throw new ValidationError(error.details[0].message);
        }

        return await this.authService.register(body);
    }

    /**
     * Refresh access token
     * @summary Get a new access token using refresh token
     * @param body Refresh token
     * @returns New access token and refresh token
     */
    @Post('refresh')
    @SuccessResponse('200', 'Token refreshed')
    @Response('401', 'Invalid or expired refresh token')
    @Example<RefreshTokenResponse>({
        token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
        refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
    })
    public async refreshToken(@Body() body: RefreshTokenRequest): Promise<RefreshTokenResponse> {
        // Validate input
        const { error } = refreshTokenSchema.validate(body);
        if (error) {
            throw new ValidationError(error.details[0].message);
        }

        return await this.authService.refreshToken(body.refreshToken);
    }

    /** 
     * Reset password request
     * @summary Request a password reset
     * @param body Email address
     * @returns Success message
     */
    @Post('reset-request')
    @SuccessResponse('200', 'Reset request successful')
    @Response('401', 'Invalid or expired refresh token')
    public async resetRequest(@Body() body: ResetRequest): Promise<{ message: string }> {
        const { error } = resetRequestSchema.validate(body);
        if (error) {
            throw new ValidationError(error.details[0].message);
        }
        return await this.authService.resetRequest(body.email);
    }

    /** 
     * Reset password
     * @summary Reset password using reset token
     * @param body Reset token and new password
     * @returns Success message
     */
    @Post('reset-password')
    @SuccessResponse('200', 'Password reset successful')
    @Response('401', 'Invalid or expired reset token')
    public async resetPassword(@Body() body: ResetPasswordRequest): Promise<{ message: string }> {
        const { error } = resetPasswordSchema.validate(body);
        if (error) {
            throw new ValidationError(error.details[0].message);
        }
        return await this.authService.resetPassword(body.token, body.password);
    }
}
