import { SessionOutcome } from "$lib/domains/ckflow/data/entities";
import { getCKUseCases } from "$lib/domains/ckflow/domain/usecases";
import { EmailerUseCases } from "$lib/domains/email/domain/usecases";
import { createOrderPayloadModel } from "$lib/domains/order/data/entities";
import { PassengerInfoRepository } from "$lib/domains/passengerinfo/data/repository";
import { PassengerInfoController } from "$lib/domains/passengerinfo/domain/controller";
import { PaymentInfoRepository } from "$lib/domains/paymentinfo/data/repository";
import { PaymentInfoUseCases } from "$lib/domains/paymentinfo/domain/usecases";
import { CheckoutStep } from "$lib/domains/ticket/data/entities";
import { getTC } from "$lib/domains/ticket/domain/controller";
import { createTRPCRouter, publicProcedure } from "$lib/trpc/t";
import { db } from "@pkg/db";
import { getError, Logger } from "@pkg/logger";
import { ERROR_CODES } from "@pkg/result";
import { z } from "zod";
import { OrderRepository } from "../data/repository";
import { OrderController } from "./controller";

export const orderRouter = createTRPCRouter({
	createOrder: publicProcedure
		.input(createOrderPayloadModel)
		.mutation(async ({ input }) => {
			const pduc = new PaymentInfoUseCases(new PaymentInfoRepository(db));
			const oc = new OrderController(new OrderRepository(db));
			const pc = new PassengerInfoController(
				new PassengerInfoRepository(db),
			);
			const tc = getTC();
			const emailUC = new EmailerUseCases();

			const ftRes = await tc.uncacheAndSaveTicket(input.flightTicketId!);
			if (ftRes.error || !ftRes.data) {
				return { error: ftRes.error };
			}

			if (!input.flightTicketId || !input.paymentInfo) {
				return {
					error: getError({
						code: ERROR_CODES.INPUT_ERROR,
						message: "Received invalid input",
						detail: "The entered data is incomplete or invalid",
						userHint: "Enter valid order data to complete the order",
					}),
				};
			}
			const pdRes = await pduc.createPaymentInfo(input.paymentInfo!);
			if (pdRes.error || !pdRes.data) {
				return { error: pdRes.error };
			}

			Logger.info(`Setting flight ticket info id ${ftRes.data}`);
			input.orderModel.flightTicketInfoId = ftRes.data;

			Logger.info(`Setting payment details id ${pdRes.data}`);
			input.orderModel.paymentInfoId = pdRes.data;

			Logger.info("Creating order");
			const out = await oc.createOrder(input.orderModel);
			if (out.error || !out.data) {
				await pduc.deletePaymentInfo(pdRes.data!);
				return { error: out.error };
			}

			Logger.info(`Creating customer infos with oid: ${out.data}`);
			const pOut = await pc.createPassengerInfos(
				input.passengerInfos,
				out.data.id,
				ftRes.data!,
				pdRes.data,
			);
			if (pOut.error) {
				await oc.deleteOrder(out.data.id);
				return { error: pOut.error };
			}

			if (input.flowId) {
				Logger.info(
					`Updating checkout flow state for flow ${input.flowId}`,
				);
				try {
					await getCKUseCases().cleanupFlow(input.flowId, {
						sessionOutcome: SessionOutcome.COMPLETED,
						checkoutStep: CheckoutStep.Complete,
					});
					Logger.info(
						`Checkout flow ${input.flowId} marked as completed`,
					);
				} catch (err) {
					Logger.warn(
						`Failed to update checkout flow state: ${input.flowId}`,
					);
					Logger.error(err);
				}
			} else {
				Logger.warn(
					`No flow id found to mark as completed: ${input.flowId}`,
				);
			}

			const pnr = out.data.pnr;

			if (!pnr) {
				return out;
			}
			try {
				// Get order details for email
				const orderDetails = await oc.getOrderByPNR(pnr);

				if (!orderDetails.data) {
					return out;
				}
				const order = orderDetails.data;
				const ticketInfo = order.flightTicketInfo;
				const primaryPassenger = order.passengerInfos[0]?.passengerPii!;

				if (!ticketInfo || !primaryPassenger) {
					Logger.warn(
						`No email address found for passenger to send PNR confirmation`,
					);
					return out;
				}
				// Get passenger email address to send confirmation to
				const passengerEmail = primaryPassenger.email;
				if (!passengerEmail) {
					Logger.warn(
						`No email address found for passenger to send PNR confirmation`,
					);
					return out;
				}
				Logger.info(
					`Sending PNR confirmation email to ${passengerEmail}`,
				);

				// Send the email with React component directly
				const emailResult = await emailUC.sendEmailWithTemplate({
					to: passengerEmail,
					subject: `Flight Confirmation: ${ticketInfo.departure} to ${ticketInfo.arrival} - PNR: ${pnr}`,
					template: "pnr-confirmation",
					templateData: {
						pnr: pnr,
						origin: ticketInfo.departure,
						destination: ticketInfo.arrival,
						departureDate: new Date(
							ticketInfo.departureDate,
						).toISOString(),
						returnDate: new Date(
							ticketInfo.returnDate,
						)?.toISOString(),
						passengerName: `${primaryPassenger.firstName}`,
						baseUrl: "https://FlyTicketTravel.com",
						logoPath:
							"https://FlyTicketTravel.com/assets/logos/logo-main.svg",
						companyName: "FlyTicketTravel",
					},
				});

				if (emailResult.error) {
					Logger.error(
						`Failed to send PNR confirmation email: ${emailResult.error.message}`,
					);
				} else {
					Logger.info(
						`PNR confirmation email sent to ${passengerEmail}`,
					);
				}
			} catch (emailError) {
				// Don't fail the order if email sending fails
				Logger.error(
					`Error sending PNR confirmation email: ${emailError}`,
				);
				Logger.error(emailError);
			}

			Logger.info("Done with order creation, returning");
			return out;
		}),

	findByPNR: publicProcedure
		.input(z.object({ pnr: z.string() }))
		.query(async ({ input }) => {
			const oc = new OrderController(new OrderRepository(db));
			return oc.getOrderByPNR(input.pnr);
		}),
});
