const express = require('express');
const router = express.Router();

import { Request, Response } from 'express';
import pool from '../db';
import { requireLogin, requireMemberState, requireRole } from '../middleware/auth';
import { getUserActiveLOA } from '../services/db/loaService';
import { getAllMembersLite, getMemberSettings, getMembersFull, getMembersLite, getUserData, getUserState, setUserSettings, getFilteredMembers, setUserState, getLastNonSuspendedState } from '../services/db/memberService';
import { getUserRoles } from '../services/db/rolesService';
import { memberSettings, MemberState, myData } from '@app/shared/types/member';
import { Discharge } from '@app/shared/schemas/dischargeSchema';

import { Performance } from 'perf_hooks';
import { logger } from '../services/logging/logger';
import { memberCache } from './auth';
import { cancelLatestRank } from '../services/db/rankService';
import { cancelLatestUnit } from '../services/db/unitService';
import { audit } from '../services/logging/auditLog';

//get all users
router.get('/', [requireLogin, requireMemberState(MemberState.Member)], async (req, res) => {
    try {
        const result = await pool.query(
            `SELECT
            v.*,
            CASE
                WHEN EXISTS (
                SELECT 1
                FROM leave_of_absences l
                WHERE l.member_id = v.member_id
                    AND l.deleted = 0
                    AND UTC_TIMESTAMP() BETWEEN l.start_date AND l.end_date
                ) THEN 1 ELSE 0
            END AS on_loa
            FROM view_member_rank_unit_status_latest v;`);
        return res.status(200).json(result);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get all users',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        return res.status(500).json({ error: 'Failed to fetch users' });
    }
});

router.get('/filtered', [requireLogin, requireMemberState(MemberState.Member)], async (req, res) => {
    try {
        // Extract Query Parameters
        const page = parseInt(req.query.page as string) || 1;
        const pageSize = parseInt(req.query.pageSize as string) || 15;
        const search = req.query.search as string | undefined;
        const status = req.query.status as string | undefined;
        const unitId = req.query.unitId as string | undefined;

        // Call the service function
        const result = await getFilteredMembers(page, pageSize, search, status, unitId);

        return res.status(200).json(result);
    } catch (error) {
        logger.error('app', 'Failed to get filtered users', {
            error: error instanceof Error ? error.message : String(error),
        });
        return res.status(500).json({ error: 'Failed to fetch users' });
    }
});

router.get('/me', [requireLogin], async (req: Request, res) => {
    if (!req.user) return res.sendStatus(401);

    const routeStart = performance.now();
    const timings: Record<string, number> = {};

    try {
        let t;

        t = performance.now();
        const memData = await getUserData(req.user.id);
        timings.member = performance.now() - t;

        t = performance.now();
        const LOAData = await getUserActiveLOA(req.user.id);
        timings.loa = performance.now() - t;

        t = performance.now();
        const memState = await getUserState(req.user.id);
        timings.state = performance.now() - t;

        t = performance.now();
        const roleData = await getUserRoles(req.user.id);
        timings.roles = performance.now() - t;

        const userDataFull: myData = {
            member: memData,
            LOAs: LOAData,
            roles: roleData,
            state: memState,
        };

        res.status(200).json(userDataFull);

        logger.info('profiling', 'GET /members/me completed', {
            userId: req.user.id,
            total_ms: performance.now() - routeStart,
            breakdown_ms: timings,
        }, 'profiling');

    } catch (error) {
        logger.error('profiling', 'GET /members/me failed', {
            userId: req.user?.id,
            error: error instanceof Error ? error.message : String(error),
        });

        return res.status(500).json({ error: 'Failed to fetch user data' });
    }
});


router.get('/settings', [requireLogin], async (req: Request, res: Response) => {
    try {
        let user = req.user.id;
        let output = await getMemberSettings(user);
        res.status(200).json(output);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get member settings',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).json(error);
    }
})

router.put('/settings', [requireLogin], async (req: Request, res: Response) => {
    try {
        let user = req.user.id;
        let settings: memberSettings = req.body;
        await setUserSettings(user, settings);
        logger.info('app', 'User updated profile settings', { user: user })
        res.sendStatus(200);
    } catch (error) {
        logger.error(
            'app',
            'Failed to update user settings',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        ); res.status(500).json(error);
    }
})

router.get('/lite', [requireLogin], async (req: Request, res: Response) => {
    try {
        let activeOnly = Boolean(req.query.active);
        console.log(activeOnly);
        let out = await getAllMembersLite(activeOnly);
        res.status(200).json(out);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get lite users',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).json(error);
    }
})

router.post('/lite/bulk', async (req: Request, res: Response) => {
    try {
        let ids = req.body.ids;
        let out = await getMembersLite(ids);
        res.status(200).json(out);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get batch lite users',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).json(error);
    }
})


router.post('/full/bulk', async (req: Request, res: Response) => {
    try {
        let ids = req.body.ids;
        let out = await getMembersFull(ids);
        res.status(200).json(out);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get batch full users',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        ); res.status(500).json(error);
    }
})

router.get('/:id', [requireLogin], async (req, res) => {
    const userId = req.params.id;

    try {
        const result = await pool.query('SELECT * FROM view_member_rank_unit_status_latest WHERE id = $1;', [userId]);
        if (result.rows.length === 0) {
            return res.status(404).json({ error: 'User not found' });
        }
        return res.status(200).json(result.rows[0]);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get user',
            {
                user: userId,
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        ); return res.status(500).json({ error: 'Failed to fetch user' });
    }
});

//update a user's display name (stub)
router.put('/:id/displayname', async (req, res) => {
    // Stub: not implemented yet
    return res.status(501);
});

//discharge member
router.post('/discharge', [requireLogin, requireMemberState(MemberState.Member), requireRole("17th Administrator")], async (req: Request, res: Response) => {
    try {
        var con = await pool.getConnection();
        let author = req.user.id;

        con.beginTransaction();

        var data: Discharge = req.body;
        setUserState(data.userID, MemberState.Discharged, "Member Discharged", author, con, data.reason);
        cancelLatestRank(data.userID, con);
        cancelLatestUnit(data.userID, con);
        con.commit();
        memberCache.Invalidate(data.userID);


        audit.member('discharged', { actorId: req.user.id, targetId: data.userID }, { reason: data.reason });

        res.sendStatus(200);
    } catch (error) {
        logger.error('app', 'Failed to discharge user', {
            data: data,
            caller: req.user.id,
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
        })
        res.sendStatus(500);
    } finally {
        if (con)
            con.release();
    }
});

//suspend member
router.post('/suspend', [requireLogin, requireMemberState(MemberState.Member), requireRole("17th Administrator")], async (req: Request, res: Response) => {
    let author = req.user.id;
    let target = Number(req.query.target);
    try {
        await setUserState(target, MemberState.Suspended, "Member Suspended", author, null);

        audit.member('suspension_added', { actorId: author, targetId: target });

        res.sendStatus(200);
    } catch (error) {
        logger.error('app', 'Failed to suspend user', {
            target: target,
            caller: req.user.id,
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
        })
        res.sendStatus(500);
    }
})

//unsuspend member
router.post('/unsuspend', [requireLogin, requireMemberState(MemberState.Member), requireRole("17th Administrator")], async (req: Request, res: Response) => {
    let author = req.user.id;
    let target = Number(req.query.target);
    try {
        let prevState = await getLastNonSuspendedState(target);
        await setUserState(target, prevState, "Member Suspension Removed", author, null);
        audit.member('suspension_removed', { actorId: author, targetId: target });

        res.sendStatus(200);
    } catch (error) {
        logger.error('app', 'Failed to suspend user', {
            target: target,
            caller: req.user.id,
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
        })
        res.sendStatus(500);
    }
})

export const memberRouter = router;
