const bcrypt = require('bcryptjs');
const crypto = require('crypto');
const AdminUserRepository = require('../repositories/AdminUserRepository');

const DEFAULT_SALT_ROUNDS = parseInt(process.env.ADMIN_PASSWORD_SALT_ROUNDS || '12', 10);

class AdminAuthService {
    async needsInitialSetup() {
        const count = await AdminUserRepository.countActiveAdmins();
        return count === 0;
    }

    async createInitialAdmin({ username, password }) {
        const trimmedUsername = (username || '').trim().toLowerCase();
        if (!trimmedUsername) {
            throw new Error('USERNAME_REQUIRED');
        }
        if (!password || password.length < 10) {
            throw new Error('PASSWORD_TOO_WEAK');
        }

        const needsSetup = await this.needsInitialSetup();
        if (!needsSetup) {
            throw new Error('SETUP_ALREADY_COMPLETED');
        }

        const passwordHash = await this.hashPassword(password);
        const id = await AdminUserRepository.createAdminUser({
            username: trimmedUsername,
            passwordHash,
            role: 'admin',
            requiresPasswordChange: false
        });

        return {
            id,
            username: trimmedUsername,
            role: 'admin'
        };
    }

    async createAdminUser({ username, password, role = 'admin', requiresPasswordChange = false }) {
        const trimmedUsername = (username || '').trim().toLowerCase();
        if (!trimmedUsername) {
            throw new Error('USERNAME_REQUIRED');
        }
        if (!password || password.length < 10) {
            throw new Error('PASSWORD_TOO_WEAK');
        }

        const normalizedRole = (role || 'admin').trim().toLowerCase();
        const targetRole = normalizedRole || 'admin';

        const existing = await AdminUserRepository.getByUsername(trimmedUsername);
        if (existing) {
            throw new Error('USERNAME_IN_USE');
        }

        const passwordHash = await this.hashPassword(password);
        const id = await AdminUserRepository.createAdminUser({
            username: trimmedUsername,
            passwordHash,
            role: targetRole,
            requiresPasswordChange
        });

        return {
            id,
            username: trimmedUsername,
            role: targetRole,
            requiresPasswordChange: Boolean(requiresPasswordChange)
        };
    }

    async changePassword({ userId, currentPassword, newPassword }) {
        if (!userId) {
            throw new Error('USER_NOT_FOUND');
        }
        if (!currentPassword) {
            throw new Error('CURRENT_PASSWORD_REQUIRED');
        }
        if (!newPassword || newPassword.length < 10) {
            throw new Error('PASSWORD_TOO_WEAK');
        }

        const userRecord = await AdminUserRepository.getById(userId);
        if (!userRecord || !userRecord.is_active) {
            throw new Error('USER_NOT_FOUND');
        }

        const matches = await bcrypt.compare(currentPassword || '', userRecord.password_hash);
        if (!matches) {
            throw new Error('INVALID_CURRENT_PASSWORD');
        }

        const passwordHash = await this.hashPassword(newPassword);
        await AdminUserRepository.updatePassword(userRecord.id, passwordHash, false);

        return {
            id: userRecord.id,
            username: userRecord.username,
            role: userRecord.role,
            requiresPasswordChange: false
        };
    }

    async hashPassword(password) {
        return bcrypt.hash(password, DEFAULT_SALT_ROUNDS);
    }

    async verifyCredentials(username, password) {
        const normalizedUsername = (username || '').trim().toLowerCase();
        const user = await AdminUserRepository.getByUsername(normalizedUsername);
        if (!user || !user.is_active) {
            return null;
        }

        const matches = await bcrypt.compare(password || '', user.password_hash);
        if (!matches) {
            return null;
        }

        await AdminUserRepository.recordSuccessfulLogin(user.id);
        return {
            id: user.id,
            username: user.username,
            role: user.role,
            requiresPasswordChange: Boolean(user.requires_password_change)
        };
    }

    generateCsrfToken() {
        return crypto.randomBytes(32).toString('hex');
    }

    startSession(req, user) {
        const csrfToken = this.generateCsrfToken();
        req.session.user = {
            id: user.id,
            username: user.username,
            role: user.role,
            requiresPasswordChange: user.requiresPasswordChange || false
        };
        req.session.csrfToken = csrfToken;
        return csrfToken;
    }

    async destroySession(req) {
        return new Promise((resolve, reject) => {
            if (!req.session) {
                return resolve();
            }
            req.session.destroy((err) => {
                if (err) {
                    reject(err);
                } else {
                    resolve();
                }
            });
        });
    }
}

module.exports = new AdminAuthService();
