import { Request, Response } from "express";
import { z } from "zod";
import { asyncHandler } from "@/core/asyncHandler";
import { AppError } from "@/core/AppError";
import { orderService } from "../order.service";
import { OrderStatus } from "@prisma/client";
import { ReplaceOrderDepositLinesSchema } from "ttm-shared";

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

const replaceItemsSchema = z.object({
    items: z.array(
        z.object({
            productId: z.string().uuid(),
            quantity: z.number().int().positive()
        })
    )
})

/* ========================
   LIST ORDERS
======================== */

export const getOrdersForShop = asyncHandler(
    async (req: Request, res: Response) => {
        const orders = await orderService.findAll(req.shop!.id);
        res.json(orders);
    }
);

/* ========================
   CREATE ORDER
======================== */

export const createOrder = asyncHandler(
    async (req: Request, res: Response) => {
        const actorId = req.auth?.sub;
        if (!actorId) {
            throw new AppError("Unauthorized", 401);
        }

        const stationId = req.body?.stationId as string | undefined;

        const order = await orderService.createDraft(
            req.shop!.id,
            actorId,
            req.senderSocketId,
            stationId
        );

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

/* ========================
   GET ORDER
======================== */

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

        const order = await orderService.findById(
            req.shop!.id,
            id
        );

        if (!order) {
            throw new AppError("Order not found", 404);
        }

        res.json(order);
    }
);

/* ========================
   REPLACE ITEMS
======================== */

export const replaceItems = asyncHandler(
    async (req: Request, res: Response) => {

        const { id } = paramsSchema.parse(req.params)
        const { items } = replaceItemsSchema.parse(req.body)

        const order = await orderService.findById(
            req.shop!.id,
            id
        )

        if (!order) {
            throw new AppError("Order not found", 404)
        }

        if (order.status === OrderStatus.PAID) {
            throw new AppError("Cannot modify a paid order", 400)
        }

        const updatedOrder = await orderService.replaceItems(
            req.shop!.id,
            id,
            items,
            req.auth?.sub,
            req.senderSocketId
        )

        res.json(updatedOrder)
    }
)

export const replaceDepositLines = asyncHandler(
    async (req: Request, res: Response) => {
        const { id } = paramsSchema.parse(req.params)
        const { lines } = ReplaceOrderDepositLinesSchema.parse(req.body)

        const order = await orderService.replaceDepositLines(
            req.shop!.id,
            id,
            lines,
            req.auth?.sub,
            req.senderSocketId,
        )

        res.json(order)
    }
)

export const updateOrder = asyncHandler(
    async (req: Request, res: Response) => {

        const { id } = paramsSchema.parse(req.params)
        const { status } = req.body

        if (!Object.values(OrderStatus).includes(status)) {
            throw new AppError("Invalid status", 400)
        }

        const updatedOrder = await orderService.updateStatus(
            req.shop!.id,
            id,
            status,
            req.auth?.sub,
            req.senderSocketId
        )

        res.json(updatedOrder)
    }
)

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

        const existing = await orderService.findById(
            req.shop!.id,
            id
        );

        if (!existing) {
            throw new AppError("Order not found", 404);
        }

        await orderService.softDelete(
            req.shop!.id,
            id
        );

        res.status(204).send();
    }
);

export const getOrdersPending = asyncHandler(
    async (req: Request, res: Response) => {

        const drafts = await orderService.getPendings(
            req.shop!.id
        );

        res.json(drafts);
    }
)