const modelUser = require('../models/users.model');
const modelApiKey = require('../models/apiKey.model');
const Transaction = require('../models/transaction.model');

const { createToken, createRefreshToken, createApiKey, verifyToken } = require('../utils/jwt');
const { jwtDecode } = require('jwt-decode');
const jwt = require('jsonwebtoken');

const { ConflictRequestError, BadRequestError } = require('../core/error.response');
const { emitToUser } = require('../socket');

const otpGenerator = require('otp-generator');
const bcrypt = require('bcrypt');
const SendMailForgotPassword = require('../utils/sendMailForgotPassword');
const LogService = require('./log.service');

class UserService {
    async createUser(data, ipAddress = 'Unknown') {
        const { fullName, email, password } = data;
        const findUser = await modelUser.findOne({ email });
        if (findUser) {
            throw new ConflictRequestError('Email đã tồn tại');
        }

        const saltRounds = 10;
        const salt = bcrypt.genSaltSync(saltRounds);
        const passwordHash = bcrypt.hashSync(password, salt);

        // Tạo user mới
        const newUser = await modelUser.create({
            fullName,
            email,
            password: passwordHash,
            typeLogin: 'email',
        });

        // Tạo API key và token
        await createApiKey(newUser._id);
        const token = await createToken({ id: newUser._id });
        const refreshToken = await createRefreshToken({ id: newUser._id });

        await LogService.createLog({
            userId: newUser._id,
            action: 'REGISTER',
            content: 'Đăng ký tài khoản thành công',
            ipAddress,
        });

        return { token, refreshToken };
    }

    async authUser(id) {
        const findUser = await modelUser.findById(id);
        if (!findUser) {
            throw new BadRequestError('User không tồn tại');
        }
        return findUser;
    }

    async login(data, ipAddress = 'Unknown') {
        const { email, password } = data;
        const user = await modelUser.findOne({ email });
        if (!user) {
            throw new BadRequestError('Tài khoản hoặc mật khẩu không chính xác');
        }
        if (user.typeLogin === 'google') {
            throw new BadRequestError('Tài khoản đăng nhập bằng google');
        }

        const checkPassword = bcrypt.compareSync(password, user.password);
        if (!checkPassword) {
            throw new BadRequestError('Tài khoản hoặc mật khẩu không chính xác');
        }
        await createApiKey(user._id);
        const token = await createToken({ id: user._id });
        const refreshToken = await createRefreshToken({ id: user._id });

        await LogService.createLog({
            userId: user._id,
            action: 'LOGIN',
            content: 'Đăng nhập thành công',
            ipAddress,
        });

        return { token, refreshToken };
    }

    async logout(id) {
        await modelApiKey.deleteMany({ userId: id });
        return { status: 200 };
    }

    async refreshToken(refreshToken) {
        const decoded = await verifyToken(refreshToken);

        const user = await modelUser.findOne({ _id: decoded.id });

        const token = await createToken({ id: user._id });
        return { token };
    }

    async getAllUser({ page = 1, limit = 10, search = '' }) {
        const skip = (page - 1) * limit;
        const query = {};

        if (search) {
            query.$or = [{ fullName: { $regex: search, $options: 'i' } }, { email: { $regex: search, $options: 'i' } }];
        }

        const users = await modelUser.find(query).skip(skip).limit(limit).sort({ createdAt: -1 });
        const total = await modelUser.countDocuments(query);

        return {
            users,
            total,
            pages: Math.ceil(total / limit),
            currentPage: Number(page),
        };
    }

    async updateUserAdmin(id, data) {
        const { fullName, email, phone, address, isAdmin, typeLogin } = data;
        const user = await modelUser.findOne({ _id: id });
        if (!user) {
            throw new BadRequestError('Tài khoản không tồn tại');
        }
        user.fullName = fullName;
        user.email = email;
        user.phone = phone;
        user.address = address;
        user.isAdmin = isAdmin;
        user.typeLogin = typeLogin;
        await user.save();
        return user;
    }

    async deleteUser(id) {
        const user = await modelUser.findOne({ _id: id });
        if (!user) {
            throw new BadRequestError('Tài khoản không tồn tại');
        }
        await user.deleteOne();
        return user;
    }

    async addBalance(id, { amount, note }) {
        const parsedAmount = Number(amount);
        if (!parsedAmount || parsedAmount <= 0) {
            throw new BadRequestError('Số tiền không hợp lệ');
        }

        const user = await modelUser.findById(id);
        if (!user) {
            throw new BadRequestError('Tài khoản không tồn tại');
        }

        const balanceBefore = user.balance;
        user.balance += parsedAmount;
        user.balanceHistory += parsedAmount;
        await user.save();

        // Ghi lịch sử giao dịch
        const generateCode = () => {
            const random = Math.random().toString(36).substring(2, 7).toUpperCase();
            const time = Date.now().toString().slice(-3);
            return `ADMIN-${random}${time}`;
        };

        await Transaction.create({
            userId: user._id,
            transCode: generateCode(),
            type: 'DEPOSIT',
            amount: parsedAmount,
            balanceBefore,
            balanceAfter: user.balance,
            content: note || `Admin cộng tiền thủ công: +${parsedAmount.toLocaleString()}đ`,
        });

        // Gửi thông báo real-time
        emitToUser(String(user._id), 'balance_updated', {
            newBalance: user.balance,
            amount: parsedAmount,
            message: `Tài khoản của bạn vừa được cộng ${parsedAmount.toLocaleString()}đ`,
        });

        return user;
    }

    async changePassword(id, data) {
        const { currentPassword, newPassword } = data;
        const user = await modelUser.findOne({ _id: id });
        if (!user) {
            throw new BadRequestError('Người dùng không tồn tại');
        }
        const isPasswordValid = bcrypt.compareSync(currentPassword, user.password);
        if (!isPasswordValid) {
            throw new BadRequestError('Mật khẩu hiện tại không chính xác');
        }
        const saltRounds = 10;
        const salt = bcrypt.genSaltSync(saltRounds);
        const passwordHash = bcrypt.hashSync(newPassword, salt);
        user.password = passwordHash;
        await user.save();

        await LogService.createLog({
            userId: user._id,
            action: 'CHANGE_PASSWORD',
            content: 'Thay đổi mật khẩu thành công',
            ipAddress: 'Unknown',
        });

        return user;
    }

    async updateUser(id, data) {
        const { fullName, address, phone, birthDay } = data; // Fix: Loại bỏ email - không cho tự đổi
        const user = await modelUser.findOne({ _id: id });
        if (!user) {
            throw new BadRequestError('Người dùng không tồn tại');
        }
        user.fullName = fullName;
        user.address = address;
        user.phone = phone;
        user.birthDay = birthDay;
        // email KHÔNG được cập nhật qua endpoint này
        await user.save();
        return user;
    }

    async uploadAvatar(id, filename) {
        const user = await modelUser.findOne({ _id: id });
        if (!user) {
            throw new BadRequestError('Người dùng không tồn tại');
        }
        user.avatar = filename;
        await user.save();
        return user;
    }

    async loginGoogle(data) {
        // Hỗ trợ 2 flow:
        // 1. credential (ID token từ Google One Tap) → dùng jwtDecode
        // 2. userInfo object (từ access_token flow) → dùng trực tiếp
        let email, name;

        if (data.userInfo) {
            email = data.userInfo.email;
            name = data.userInfo.name;
        } else {
            const dataToken = jwtDecode(data.credential || data);
            email = dataToken.email;
            name = dataToken.name;
        }

        if (!email) {
            throw new BadRequestError('Không lấy được thông tin email từ Google');
        }

        const user = await modelUser.findOne({ email });

        if (user) {
            await createApiKey(user._id);
            const token = await createToken({ id: user._id });
            const refreshToken = await createRefreshToken({ id: user._id });
            return { token, refreshToken };
        } else {
            const newUser = await modelUser.create({
                email,
                typeLogin: 'google',
                fullName: name || email,
                password: bcrypt.hashSync(Math.random().toString(36), 10),
            });
            await createApiKey(newUser._id);
            const token = await createToken({ id: newUser._id });
            const refreshToken = await createRefreshToken({ id: newUser._id });
            return { token, refreshToken };
        }
    }


    async forgotPassword(email) {
        const user = await modelUser.findOne({ email });
        if (!user) {
            throw new BadRequestError('Tài khoản không tồn tại');
        }

        const token = jwt.sign({ id: user._id }, process.env.SECRET_CRYPTO, { expiresIn: '5m' });

        const otp = otpGenerator.generate(6, {
            digits: true,
            lowerCaseAlphabets: false,
            upperCaseAlphabets: false,
            specialChars: false,
        });

        const saltRounds = 10;

        const otpHash = bcrypt.hashSync(otp, saltRounds);

        await modelOtp.create({ email: user.email, otp: otpHash });

        await SendMailForgotPassword(user.email, otp);

        return { token, otp };
    }

    async resetPassword(token, otpUser, newPassword) {
        const decoded = jwt.verify(token, process.env.SECRET_CRYPTO);
        const user = await modelUser.findOne({ _id: decoded.id });

        if (!user) {
            throw new BadRequestError('Tài khoản không tồn tại');
        }
        const findOtp = await modelOtp.findOne({ email: user.email }).sort({ createdAt: -1 });

        if (!findOtp) {
            throw new BadRequestError('Mã OTP không hợp lệ');
        }

        const checkOtp = bcrypt.compareSync(otpUser, findOtp.otp);
        if (!checkOtp) {
            throw new BadRequestError('Mã OTP không hợp lệ');
        }
        const saltRounds = 10;
        const salt = bcrypt.genSaltSync(saltRounds);
        const passwordHash = bcrypt.hashSync(newPassword, salt);
        user.password = passwordHash;
        await user.save();
        return user;
    }

    async chatbot(question, userId) {
        const response = await askHotelAssistant(question);

        await modelMessageChatbot.create({
            userId: userId,
            sender: 'user',
            content: question,
        });

        await modelMessageChatbot.create({
            userId: userId,
            sender: 'bot',
            content: response,
        });

        return response;
    }

    async getMessageChatbot(userId) {
        const messageChatbot = await modelMessageChatbot.find({ userId });
        return messageChatbot;
    }
}

module.exports = new UserService();
