import { prisma } from '../config/database';
import { Prisma } from '@prisma/client';
import { config } from '../config';
import { logger } from '../config/logger';
import jwt from 'jsonwebtoken';
import {
    ListUsersResponse,
    GetUserResponse,
    UpdateUser,
    UpdateRoleResponse,
    DeactivateAccountResponse,
    ActivateAccountResponse,
} from '../types/usersmanagement.types';
import { UserResponse } from '../types/user.types';
import { UnauthorizedError, ValidationError, ForbiddenError } from '../middleware/errorHandler';
import { getPresignedUrl } from '../config/minio';

export class UserManagementService {
    async listUsers(): Promise<ListUsersResponse> {
        try {
            const users = await prisma.user.findMany({
                where: {
                    is_deactivated: false
                },
                include: {
                    profile: true,
                    role: true,

                }
            });

            return {
                code: 200,
                message: 'Users fetched successfully',
                total: users.length,
                data: await Promise.all(users.map(user => this.formatUserResponse(user)))
            };
        } catch (error) {
            logger.error('Failed to fetch users', { error });
            throw error;
        }
    }


    async getUserById(id: number): Promise<GetUserResponse> {
        try {
            const user = await prisma.user.findUnique({
                where: { id },
                include: {
                    role: true,
                    profile: true
                }
            });
            if (!user) throw new UnauthorizedError('User not found');
            return {
                code: 200,
                message: 'User fetched successfully',
                data: await this.formatUserResponse(user)
            };
        } catch (error) {
            logger.error('Failed to fetch user by ID', { error });
            throw error;
        }
    }

    async updateUserRole(id: number, role_id: number): Promise<UpdateRoleResponse> {
        try {
            const user = await prisma.user.findUnique({ where: { id } });
            if (!user) throw new UnauthorizedError('User not found');

            const role = await prisma.role.findUnique({ where: { id: role_id } });
            if (!role) throw new UnauthorizedError('Role not found');

            await prisma.user.update({
                where: { id },
                data: { role_id }
            });

            return {
                code: 200,
                message: 'User role updated successfully'
            };
        } catch (error) {
            logger.error('Failed to update user role', { error });
            throw error;
        }
    }

    async deleteUser(id: number): Promise<DeactivateAccountResponse> {
        try {
            const user = await prisma.user.findUnique({ where: { id } });
            if (!user) throw new UnauthorizedError('User not found');

            await prisma.user.update({
                where: { id },
                data: { is_deactivated: true }
            });
            return {
                code: 200,
                message: 'User deactivated successfully'
            };
        } catch (error) {
            logger.error('Failed to deactivate user', { error });
            throw error;
        }
    }

    async deactivateAccount(id: number): Promise<DeactivateAccountResponse> {
        try {
            const user = await prisma.user.findUnique({ where: { id } });
            if (!user) throw new UnauthorizedError('User not found');

            if (user.is_deactivated) {
                logger.warn('Deactivate attempt with deactivated account', { userId: user.id });
                throw new ForbiddenError('This account has already been deactivated');
            }

            // Deactivate account
            await prisma.user.update({
                where: { id: user.id },
                data: { is_deactivated: true }
            });

            logger.info('Account deactivated successfully', { userId: user.id });
            return {
                code: 200,
                message: 'Account deactivated successfully'
            };
        } catch (error) {
            if (error instanceof jwt.JsonWebTokenError) {
                logger.error('Invalid JWT token:', error);
                throw new UnauthorizedError('Invalid token');
            }
            if (error instanceof jwt.TokenExpiredError) {
                logger.error('JWT token expired:', error);
                throw new UnauthorizedError('Token expired');
            }
            logger.error('Failed to deactivate account', { error });
            throw error;
        }
    }

    async activateAccount(id: number): Promise<ActivateAccountResponse> {
        try {
            const user = await prisma.user.findUnique({ where: { id } });
            if (!user) throw new UnauthorizedError('User not found');

            // Check if account is already activated
            if (!user.is_deactivated) {
                logger.warn('Activate attempt with activated account', { userId: user.id });
                throw new ForbiddenError('This account has already been activated');
            }

            // Activate account
            await prisma.user.update({
                where: { id: user.id },
                data: { is_deactivated: false }
            });

            logger.info('Account activated successfully', { userId: user.id });
            return {
                code: 200,
                message: 'Account activated successfully'
            };
        } catch (error) {
            if (error instanceof jwt.JsonWebTokenError) {
                logger.error('Invalid JWT token:', error);
                throw new UnauthorizedError('Invalid token');
            }
            if (error instanceof jwt.TokenExpiredError) {
                logger.error('JWT token expired:', error);
                throw new UnauthorizedError('Token expired');
            }
            logger.error('Failed to activate account', { error });
            throw error;
        }
    }

    /**
     * Format user response
     */
    private async formatUserResponse(user: any): Promise<UserResponse> {
        return {
            id: user.id,
            username: user.username,
            email: user.email,
            email_verified_at: user.email_verified_at,
            created_at: user.created_at,
            updated_at: user.updated_at,
            role: {
                code: user.role.code,
                name: user.role.name as { th: string; en: string }
            },
            profile: user.profile ? {
                prefix: user.profile.prefix as { th?: string; en?: string } | undefined,
                first_name: user.profile.first_name,
                last_name: user.profile.last_name,
                avatar_url: user.profile.avatar_url ? await this.getAvatarPresignedUrl(user.profile.avatar_url) : null,
                birth_date: user.profile.birth_date,
                phone: user.profile.phone
            } : undefined
        };
    }

    /**
     * Get presigned URL for avatar
     */
    private async getAvatarPresignedUrl(avatarPath: string): Promise<string> {
        try {
            return await getPresignedUrl(avatarPath, 3600); // 1 hour expiry
        } catch (error) {
            logger.warn(`Failed to generate presigned URL for avatar: ${error}`);
            throw error;
        }
    }
}
