import { Request, Response } from "express";
import { z } from "zod";
import { asyncHandler } from "../../core/asyncHandler";
import {
    CashSessionHistoryQuerySchema,
    CloseCashSessionSchema,
    CreateCashSessionDraftSchema,
    CreateCashSessionOperationSchema,
    CreateDepositRefundSchema,
    FinalizeCashSessionDraftSchema,
    OpenCashSessionSchema,
    UpdateCashSessionSchema,
} from "ttm-shared";
import { cashSessionService } from "./cashSession.service";

const SessionIdParamsSchema = z.object({
    id: z.string().uuid()
});

const StationQuerySchema = z.object({
    stationId: z.string().uuid().optional()
});

const LatestStationQuerySchema = z.object({
    stationId: z.string().uuid()
});

/* =====================
   GET CURRENT SESSION
===================== */

export const getCurrentSession = asyncHandler(
    async (req: Request, res: Response) => {
        const { stationId } = StationQuerySchema.parse(req.query);
        const session = await cashSessionService.getCurrent(req.shop!.id, req.auth!.sub, stationId);
        res.json(session);
    }
);

/* =====================
   GET LATEST SESSION
===================== */

export const getLatestSession = asyncHandler(
    async (req: Request, res: Response) => {
        const { stationId } = LatestStationQuerySchema.parse(req.query);
        const session = await cashSessionService.getLatest(req.shop!.id, req.auth!.sub, stationId);
        res.json(session);
    }
);

/* =====================
   GET ALL OPEN SESSIONS
===================== */

export const getAllOpenSessions = asyncHandler(
    async (req: Request, res: Response) => {
        const sessions = await cashSessionService.getAllOpen(req.shop!.id, req.auth!.sub);
        res.json(sessions);
    }
);

/* =====================
   GET CURRENT DRAFT SESSION
===================== */

export const getDraftSession = asyncHandler(
    async (req: Request, res: Response) => {
        const { stationId } = StationQuerySchema.parse(req.query);
        const session = await cashSessionService.getDraft(req.shop!.id, req.auth!.sub, stationId);
        res.json(session);
    }
);

/* =====================
   GET SESSION HISTORY
===================== */

export const getSessionHistory = asyncHandler(
    async (req: Request, res: Response) => {
        const query = CashSessionHistoryQuerySchema.parse(req.query);
        const sessions = await cashSessionService.getHistory(req.shop!.id, req.auth!.sub, query);
        res.json(sessions);
    }
);

/* =====================
   GET SESSION OPERATIONS
===================== */

export const getSessionOperations = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);
        const operations = await cashSessionService.getOperations(req.shop!.id, req.auth!.sub, id);
        res.json(operations);
    }
);

/* =====================
   CREATE DRAFT SESSION
===================== */

export const createDraftSession = asyncHandler(
    async (req: Request, res: Response) => {
        const input = CreateCashSessionDraftSchema.parse(req.body);

        const session = await cashSessionService.createDraft(
            req.shop!.id,
            req.auth!.sub,
            input,
        );

        res.status(201).json(session);
    }
);

/* =====================
   OPEN SESSION
===================== */

export const openSession = asyncHandler(
    async (req: Request, res: Response) => {
        const input = OpenCashSessionSchema.parse(req.body);

        const session = await cashSessionService.open(
            req.shop!.id,
            req.auth!.sub,
            input,
            req.senderSocketId
        );

        res.status(201).json(session);
    }
);

/* =====================
   UPDATE SESSION
===================== */

export const updateSession = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);
        const input = UpdateCashSessionSchema.parse(req.body);

        const session = await cashSessionService.update(
            req.shop!.id,
            req.auth!.sub,
            id,
            input,
            req.senderSocketId
        );

        res.json(session);
    }
);

/* =====================
   FINALIZE DRAFT SESSION
===================== */

export const finalizeDraftSession = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);
        const input = FinalizeCashSessionDraftSchema.parse(req.body);

        const session = await cashSessionService.finalizeDraft(
            req.shop!.id,
            req.auth!.sub,
            id,
            input,
            req.senderSocketId,
        );

        res.json(session);
    }
);

/* =====================
   DISCARD DRAFT SESSION
===================== */

export const discardDraftSession = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);

        await cashSessionService.discardDraft(req.shop!.id, req.auth!.sub, id);
        res.status(204).send();
    }
);

/* =====================
   CREATE MANUAL OPERATION
===================== */

export const createSessionOperation = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);
        const input = CreateCashSessionOperationSchema.parse(req.body);

        const result = await cashSessionService.createOperation(
            req.shop!.id,
            req.auth!.sub,
            id,
            input,
            req.senderSocketId,
        );

        res.status(201).json(result);
    }
);

export const createDepositRefund = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);
        const input = CreateDepositRefundSchema.parse(req.body);

        const result = await cashSessionService.createDepositRefund(
            req.shop!.id,
            req.auth!.sub,
            id,
            input,
            req.senderSocketId,
        );

        res.status(201).json(result);
    }
);

export const undoLastDepositRefund = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);

        const result = await cashSessionService.undoLastDepositRefund(
            req.shop!.id,
            req.auth!.sub,
            id,
            req.senderSocketId,
        );

        res.status(201).json(result);
    }
);

/* =====================
   REOPEN SESSION
===================== */

export const reopenSession = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);

        const session = await cashSessionService.reopen(
            req.shop!.id,
            req.auth!.sub,
            id,
            req.senderSocketId
        );

        res.json(session);
    }
);

/* =====================
   CLOSE SESSION
===================== */

export const closeSession = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = SessionIdParamsSchema.parse(req.params);
        const input = CloseCashSessionSchema.parse(req.body);

        const session = await cashSessionService.closeById(
            req.shop!.id,
            req.auth!.sub,
            id,
            input,
            req.senderSocketId
        );

        res.json(session);
    }
);