import { Request, Response } from "express";
import { createEvent, getEventAttendance, getEventDetails, getShortEventsInRange, setAttendanceStatus, setEventCancelled, updateEvent } from "../services/db/calendarService";
import { CalendarAttendance, CalendarEvent } from "@app/shared/types/calendar";
import { requireLogin, requireMemberState, requireRole } from "../middleware/auth";
import { MemberState } from "@app/shared/types/member";
import { logger } from "../services/logging/logger";
import { audit } from "../services/logging/auditLog";

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

function addMonths(date: Date, months: number): Date {
    const d = new Date(date)
    d.setMonth(d.getMonth() + months)
    return d
}

//get calendar events paged, requires a query string with from= and to= as mariadb ISO strings
r.get('/', async (req, res) => {
    try {
        const fromDate: string = req.query.from;
        const toDate: string = req.query.to;

        if (fromDate === undefined || toDate === undefined) {
            res.status(400).send("Missing required query parameters 'from' and 'to'");
            return;
        }

        const events = await getShortEventsInRange(fromDate, toDate);

        res.status(200).json(events);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get calendar events',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).send('Error fetching calendar events');
    }
});

r.get('/upcoming', async (req, res) => {
    res.sendStatus(501);
})

r.post('/:id/cancel', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => {
    let member = req.user.id;
    try {
        const eventID = Number(req.params.id);
        await setEventCancelled(eventID, true);

        audit.calendar('cancelled', { actorId: member, targetId: eventID });
        logger.info('app', 'Calendar event cancelled', {
            event: eventID,
            user: req.user.id
        })
        res.sendStatus(200);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get cancel calendar event',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).send('Error setting cancel status');
    }
})
r.post('/:id/uncancel', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => {
    let member = req.user.id;
    try {
        const eventID = Number(req.params.id);
        setEventCancelled(eventID, false);

        audit.calendar('un-cancelled', { actorId: member, targetId: eventID });
        logger.info('app', 'Calendar event un-cancelled', {
            event: eventID,
            user: req.user.id
        })
        res.sendStatus(200);
    } catch (error) {
        logger.error(
            'app',
            'Failed to uncancel calendar event',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500).send('Error setting cancel status');
    }
})


r.post('/:id/attendance', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => {
    try {
        let member = req.user.id;
        let event = Number(req.params.id);
        let state = req.query.state as CalendarAttendance;
        await setAttendanceStatus(member, event, state);

        audit.calendar('attendance_set', { actorId: member, targetId: event }, { attendanceState: state });
        logger.info('app', 'Member set calendar event attendance', {
            event: event,
            user: req.user.id,
            state: state
        })

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

//get event details
r.get('/:id', async (req: Request, res: Response) => {
    try {
        const eventID: number = Number(req.params.id);

        let details: CalendarEvent = await getEventDetails(eventID);
        details.eventSignups = await getEventAttendance(eventID);
        res.status(200).json(details);
    } catch (error) {
        logger.error(
            'app',
            'Failed to get calendar event details',
            {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
            }
        );
        res.status(500);
    }
})


//post a new calendar event 
r.post('/', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => {
    try {
        const member = req.user.id;
        let event: CalendarEvent = req.body;
        event.creator_id = member;
        event.start = new Date(event.start);
        event.end = new Date(event.end);
        let eventID = await createEvent(event);
        audit.calendar('event_created', { actorId: member, targetId: eventID });
        logger.info('app', 'Calendar event posted', {
            event: event.id,
            user: req.user.id
        })

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

r.put('/', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => {
    let member = req.user.id;
    try {
        let event: CalendarEvent = req.body;
        event.start = new Date(event.start);
        event.end = new Date(event.end);
        updateEvent(event);

        audit.calendar('event_updated', { actorId: member, targetId: event.id });
        logger.info('app', 'Calendar event updated', {
            event: event.id,
            user: req.user.id
        })

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

export const calendarRouter = r;
