const UserService = require('../services/user.service');
const Role = require('../models/Role');
const AuditLog = require('../models/AuditLog');
const User = require('../models/User');
const { asyncHandler } = require('../middleware/errorHandler');
const { getAzureGroups, getAzureGroupMembers, invalidateUserSessions } = require('../services/graph.service');
const Database = require('better-sqlite3');
const path = require('path');
const DB_PATH = process.env.DATABASE_PATH || './database.sqlite';

class UserController {
    /**
     * Get all users
     * GET /api/users
     */
    static getAllUsers = asyncHandler(async (req, res) => {
        const users = UserService.getAllUsers();

        res.json({
            status: 'success',
            data: users
        });
    });

    /**
     * Get user by ID
     * GET /api/users/:id
     */
    static getUserById = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const user = UserService.getUserById(parseInt(id));

        res.json({
            status: 'success',
            data: user
        });
    });

    /**
     * Create new user
     * POST /api/users
     */
    static createUser = asyncHandler(async (req, res) => {
        const user = await UserService.createUser(
            req.body,
            req.user.id,
            req.ip
        );

        res.status(201).json({
            status: 'success',
            data: user
        });
    });

    /**
     * Update user
     * PUT /api/users/:id
     */
    static updateUser = asyncHandler(async (req, res) => {
        const { id } = req.params;

        const user = await UserService.updateUser(
            parseInt(id),
            req.body,
            req.user.id,
            req.ip
        );

        res.json({
            status: 'success',
            data: user
        });
    });

    /**
     * Delete user
     * DELETE /api/users/:id
     */
    static deleteUser = asyncHandler(async (req, res) => {
        const { id } = req.params;

        const deleted = UserService.deleteUser(
            parseInt(id),
            req.user.id,
            req.ip
        );

        if (!deleted) {
            return res.status(404).json({
                status: 'error',
                message: 'User not found'
            });
        }

        res.json({
            status: 'success',
            message: 'User deleted successfully'
        });
    });

    /**
     * Assign role to user
     * PUT /api/users/:id/role
     */
    static assignRole = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const { role_id } = req.body;

        if (!role_id) {
            return res.status(400).json({
                status: 'error',
                message: 'role_id is required'
            });
        }

        const user = UserService.assignRole(
            parseInt(id),
            role_id,
            req.user.id,
            req.ip
        );

        res.json({
            status: 'success',
            data: user
        });
    });

    /**
     * Activate/Deactivate user
     * PUT /api/users/:id/activate
     */
    static toggleUserStatus = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const { is_active } = req.body;

        if (is_active === undefined) {
            return res.status(400).json({
                status: 'error',
                message: 'is_active is required'
            });
        }

        const user = UserService.toggleUserStatus(
            parseInt(id),
            is_active,
            req.user.id,
            req.ip
        );

        res.json({
            status: 'success',
            data: user
        });
    });

    /**
     * Get all roles
     * GET /api/roles
     */
    static getAllRoles = asyncHandler(async (req, res) => {
        const roles = Role.getAll();

        res.json({
            status: 'success',
            data: roles
        });
    });

    /**
     * Get audit logs
     * GET /api/audit-logs
     */
    static getAuditLogs = asyncHandler(async (req, res) => {
        const limit = parseInt(req.query.limit) || 100;
        const offset = parseInt(req.query.offset) || 0;

        const logs = AuditLog.getAll(limit, offset);

        res.json({
            status: 'success',
            data: logs
        });
    });

    /**
     * Get audit logs for specific user
     * GET /api/audit-logs/user/:userId
     */
    static getAuditLogsByUser = asyncHandler(async (req, res) => {
        const { userId } = req.params;
        const limit = parseInt(req.query.limit) || 100;
        const offset = parseInt(req.query.offset) || 0;

        const logs = AuditLog.getByUserId(parseInt(userId), limit, offset);

        res.json({
            status: 'success',
            data: logs
        });
    });

    /**
     * Get audit logs for specific entity
     * GET /api/audit-logs/entity/:type/:id
     */
    static getAuditLogsByEntity = asyncHandler(async (req, res) => {
        const { type, id } = req.params;
        const limit = parseInt(req.query.limit) || 100;
        const offset = parseInt(req.query.offset) || 0;

        const logs = AuditLog.getByEntity(type, parseInt(id), limit, offset);

        res.json({
            status: 'success',
            data: logs
        });
    });

    /**
     * List available Azure AD groups for import selection
     * GET /api/users/import/azure/groups
     */
    static getAzureGroupsList = asyncHandler(async (req, res) => {
        let groups;
        try {
            groups = await getAzureGroups();
        } catch (err) {
            return res.status(502).json({ status: 'error', message: err.message });
        }
        res.json({ status: 'success', data: groups });
    });

    /**
     * Import users from an Azure AD group
     * POST /api/users/import/azure
     * Body: { group_id, role_id }
     */
    static importFromAzure = asyncHandler(async (req, res) => {
        const { group_id, role_id } = req.body;

        if (!group_id) {
            return res.status(400).json({ status: 'error', message: 'group_id ist erforderlich' });
        }

        if (!role_id) {
            return res.status(400).json({ status: 'error', message: 'role_id ist erforderlich' });
        }

        let members;
        try {
            members = await getAzureGroupMembers(group_id);
        } catch (err) {
            return res.status(502).json({ status: 'error', message: err.message });
        }

        const results = { imported: 0, skipped: 0, errors: [] };

        for (const member of members) {
            try {
                const email = (member.mail || member.userPrincipalName || '').toLowerCase().trim();
                if (!email) { results.skipped++; continue; }

                // Skip if already exists (by azure_id or email)
                const byAzureId = member.id ? User.getByAzureId(member.id) : null;
                if (byAzureId) { results.skipped++; continue; }

                const byEmail = User.getByEmail(email);
                if (byEmail) {
                    // Link azure_id if not yet set
                    if (!byEmail.azure_id && member.id) {
                        User.update(byEmail.id, { azure_id: member.id });
                    }
                    results.skipped++;
                    continue;
                }

                // Derive username from email prefix, ensure uniqueness by appending number if needed
                let baseUsername = email.split('@')[0].replace(/[^a-z0-9._-]/gi, '').toLowerCase();
                let username = baseUsername;
                let suffix = 1;
                while (User.getByUsername(username)) {
                    username = `${baseUsername}${suffix++}`;
                }

                const newUser = User.create({
                    username,
                    email,
                    password_hash: 'AZURE_SSO_NO_PASSWORD',
                    role_id: parseInt(role_id),
                    first_name: member.givenName || null,
                    last_name: member.surname || null,
                    is_active: true,
                    must_change_password: false,
                });
                if (member.id) {
                    User.update(newUser.id, { azure_id: member.id });
                }

                results.imported++;
            } catch (err) {
                results.errors.push({ user: member.mail || member.userPrincipalName, error: err.message });
            }
        }

        res.json({ status: 'success', data: results });
    });

    /**
     * Get full user profile: user + asset count + fido count + lifecycle status
     * GET /api/users/:id/full
     */
    static getUserFull = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const db = new Database(DB_PATH);

        const user = db.prepare(`
            SELECT u.*, r.name as role_name,
                   m.username as manager_username,
                   m.first_name as manager_first_name,
                   m.last_name as manager_last_name
            FROM users u
            LEFT JOIN roles r ON u.role_id = r.id
            LEFT JOIN users m ON u.manager_id = m.id
            WHERE u.id = ?
        `).get(parseInt(id));

        if (!user) return res.status(404).json({ status: 'error', message: 'User not found' });

        const assetCount = db.prepare(`
            SELECT COUNT(*) as cnt FROM assets
            WHERE assigned_to_user_id = ? OR assigned_to_username = ?
        `).get(parseInt(id), user.username);

        const assetStats = db.prepare(`
            SELECT
                COUNT(*) as total,
                COALESCE(SUM(purchase_price), 0) as total_value,
                MIN(purchase_date) as oldest_date
            FROM assets
            WHERE assigned_to_user_id = ? OR assigned_to_username = ?
        `).get(parseInt(id), user.username);

        const fidoCount = db.prepare(
            `SELECT COUNT(*) as cnt FROM fido_keys WHERE assigned_to_user_id = ? AND status = 'aktiv'`
        ).get(parseInt(id));

        const onboarding = db.prepare(
            `SELECT * FROM onboarding_protocols WHERE employee_user_id = ? ORDER BY created_at DESC LIMIT 1`
        ).get(parseInt(id));

        const offboarding = db.prepare(
            `SELECT * FROM offboarding_protocols WHERE employee_user_id = ? ORDER BY created_at DESC LIMIT 1`
        ).get(parseInt(id));

        let lifecycleStage = 3; // Aktiv (default for existing staff)
        if (offboarding) lifecycleStage = 5;
        else if (onboarding?.status === 'in_progress') lifecycleStage = 2;
        else if (onboarding?.status === 'pending') lifecycleStage = 1;

        delete user.password_hash;

        res.json({
            status: 'success',
            data: {
                ...user,
                asset_count: assetCount?.cnt || 0,
                asset_total_value: assetStats?.total_value || 0,
                asset_oldest_date: assetStats?.oldest_date || null,
                fido_count: fidoCount?.cnt || 0,
                lifecycle_stage: lifecycleStage,
                onboarding_protocol: onboarding || null,
                offboarding_protocol: offboarding || null,
            }
        });
    });

    /**
     * Invalidate Entra sessions (password reset via Entra SSPR)
     * POST /api/users/:id/reset-entra
     */
    static resetPasswordEntra = asyncHandler(async (req, res) => {
        const { id } = req.params;
        const user = UserService.getUserById(parseInt(id));

        if (!user?.azure_id) {
            return res.status(400).json({
                status: 'error',
                message: 'Kein Azure-Konto verknüpft. Passwort-Reset nur für Entra-Benutzer möglich.'
            });
        }

        try {
            await invalidateUserSessions(user.azure_id);
            res.json({ status: 'success', message: 'Entra-Sessions invalidiert. Benutzer wird beim nächsten Login zu Passwort-Reset aufgefordert.' });
        } catch (err) {
            res.status(502).json({ status: 'error', message: err.message });
        }
    });

    /**
     * Export all users as CSV
     * GET /api/users/export/csv
     */
    static exportCsv = asyncHandler(async (req, res) => {
        const users = UserService.getAllUsers();
        const header = 'ID,Username,Email,Vorname,Nachname,Rolle,Abteilung,Position,Telefon,Standort,Eintrittsdatum,Aktiv';
        const rows = users.map(u => [
            u.id, u.username, u.email, u.first_name || '', u.last_name || '',
            u.role_name || '', u.department || '', u.position || '',
            u.phone || '', u.location || '', u.joined_date || '', u.is_active ? 'Ja' : 'Nein'
        ].map(v => `"${String(v).replace(/"/g, '""')}"`).join(','));
        res.setHeader('Content-Type', 'text/csv; charset=utf-8');
        res.setHeader('Content-Disposition', 'attachment; filename="benutzer.csv"');
        res.send('﻿' + header + '\n' + rows.join('\n'));
    });
}

module.exports = UserController;
