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

import { Request, Response } from 'express';
import pool from '../db';
import { closeLOA, createNewLOA, getAllLOA, getLOAbyID, getLoaTypes, getUserLOA, setLOAExtension } from '../services/db/loaService';
import { LOARequest } from '@app/shared/types/loa';
import { requireLogin, requireRole } from '../middleware/auth';
import { logger } from '../services/logging/logger';
import { audit } from '../services/logging/auditLog';

router.use(requireLogin);

//member posts LOA
router.post("/", async (req: Request, res: Response) => {
    let LOARequest = req.body as LOARequest;
    LOARequest.member_id = req.user.id;
    LOARequest.created_by = req.user.id;
    LOARequest.filed_date = new Date();

    try {
        let loaID = await createNewLOA(LOARequest);

        audit.leaveOfAbsence('created', { actorId: req.user.id, targetId: loaID })
        logger.info('app', 'LOA Posted', { poster: req.user.id, user: LOARequest.member_id })
        res.sendStatus(201);
    } catch (error) {
        logger.error(
            'app',
            'Failed to post LOA',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).send(error);
    }
});

//admin posts LOA
router.post("/admin", [requireRole(['17th Administrator', '17th HQ', '17th Command'])], async (req: Request, res: Response) => {
    let LOARequest = req.body as LOARequest;
    LOARequest.created_by = req.user.id;
    LOARequest.filed_date = new Date();
    try {
        let loaID = await createNewLOA(LOARequest);
        audit.leaveOfAbsence('admin_created', { actorId: req.user.id, targetId: loaID }, { for: LOARequest.member_id })
        logger.info('app', 'LOA Posted', { poster: req.user.id, user: LOARequest.member_id })
        res.sendStatus(201);
    } catch (error) {
        logger.error(
            'app',
            'Failed to post LOA',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        ); res.status(500).send(error);
    }
});

//get my current LOA
router.get("/me", async (req: Request, res: Response) => {
    const user = req.user.id;
    try {
        const result = await getUserLOA(user);
        res.status(200).json(result)
    } catch (error) {
        logger.error(
            'app',
            'Failed to get user current LOA',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).send(error);
    }
})

//get my LOA history
router.get("/history", async (req: Request, res: Response) => {
    try {
        const user = req.user.id;

        const page = Number(req.query.page) || undefined;
        const pageSize = Number(req.query.pageSize) || undefined;

        const result = await getUserLOA(user, page, pageSize);
        res.status(200).json(result)
    } catch (error) {
        logger.error(
            'app',
            'Failed to get user LOA history',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).send(error);
    }
})

router.get('/all', [requireRole(['17th Administrator', '17th HQ', '17th Command'])], async (req: Request, res: Response) => {
    try {
        const page = Number(req.query.page) || undefined;
        const pageSize = Number(req.query.pageSize) || undefined;
        const result = await getAllLOA(page, pageSize);
        res.status(200).json(result)
    } catch (error) {
        logger.error(
            'app',
            'Failed to get full LOA history',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).send(error);
    }
})

router.get('/types', async (req: Request, res: Response) => {
    try {
        let out = await getLoaTypes();
        res.status(200).json(out);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get LOA types',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).json(error);
    }
})

router.post('/cancel/:id', async (req: Request, res: Response) => {
    let closer = req.user.id;
    let id = Number(req.params.id);
    try {
        let loa = await getLOAbyID(id);
        if (loa.member_id != closer) {
            return res.sendStatus(403);
        }

        await closeLOA(Number(req.params.id), closer);

        audit.leaveOfAbsence('ended', { actorId: req.user.id, targetId: id });
        logger.info('app', 'LOA Closed', { closed_by: closer, LOA: id })

        res.sendStatus(200);
    } catch (error) {
        logger.error(
            'app',
            'Failed to cancel LOA',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).json(error);
    }
})

//TODO: enforce admin only
router.post('/adminCancel/:id', [requireRole(['17th Administrator', '17th HQ', '17th Command'])], async (req: Request, res: Response) => {
    let closer = req.user.id;
    try {
        await closeLOA(Number(req.params.id), closer);

        audit.leaveOfAbsence('admin_ended', { actorId: req.user.id, targetId: Number(req.params.id) });
        logger.info('app', 'LOA Closed', { closed_by: closer, LOA: req.params.id })

        res.sendStatus(200);
    } catch (error) {
        logger.error(
            'app',
            'Failed to cancel LOA',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).json(error);
    }
})

// extend LOA
router.post('/extend/:id', [requireRole(['17th Administrator', '17th HQ', '17th Command'])], async (req: Request, res: Response) => {
    const to: Date = req.body.to;

    if (!to) {
        res.status(400).send("Extension length is required");
    }

    try {
        await setLOAExtension(Number(req.params.id), to);

        audit.leaveOfAbsence('extended', { actorId: req.user.id, targetId: Number(req.params.id) });
        logger.info('app', 'LOA Extended', { extended_by: req.user.id, LOA: req.params.id })

        res.sendStatus(200);
    } catch (error) {
        logger.error(
            'app',
            'Failed to extend LOA',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).json(error);
    }
})

// GET /policy
router.get('/policy', async (req: Request, res: Response) => {
    const t0 = performance.now();

    try {
        const response = await fetch(`${process.env.DOC_HOST}/api/pages/42`, {
            headers: {
                Authorization: `Token ${process.env.DOC_TOKEN_ID}:${process.env.DOC_TOKEN_SECRET}`,
            },
        });

        if (!response.ok) {
            const text = await response.text();

            logger.error('app', 'Failed to fetch policy page from Bookstack', {
                pageId: 42,
                status: response.status,
                statusText: response.statusText,
                body: text,
                userId: req.user?.id,
            });

            return res.sendStatus(500);
        }

        const out = await response.json();
        res.status(200).json(out.html);

        logger.info(
            'profiling',
            'GET /policy completed',
            {
                pageId: 42,
                total_ms: performance.now() - t0,
            },
            'profiling'
        );

    } catch (error) {
        logger.error('app', 'Error fetching policy page from Bookstack', {
            pageId: 42,
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
            userId: req.user?.id,
        });

        res.sendStatus(500);
    }
});


export const loaRouter = router;