import {
	customerInfoModel,
	type CustomerInfoModel,
} from "$lib/domains/customerinfo/data";
import { CheckoutStep } from "$lib/domains/order/data/entities";
import {
	paymentInfoPayloadModel,
	type PaymentInfoPayload,
} from "$lib/domains/paymentinfo/data/entities";
import { createTRPCRouter, publicProcedure } from "$lib/trpc/t";
import { nanoid } from "nanoid";
import { z } from "zod";
import {
	feCreateCheckoutFlowPayloadModel,
	flowInfoModel,
	SessionOutcome,
	type PaymentFlowStepPayload,
	type PrePaymentFlowStepPayload,
} from "../data/entities";
import { getCKUseCases } from "./usecases";

function getIPFromHeaders(headers: Headers): string {
	const ip = headers.get("x-forwarded-for");
	if (ip) {
		return ip;
	}
	const ip2 = headers.get("cf-connecting-ip");
	if (ip2) {
		return ip2;
	}
	return headers.get("x-real-ip") ?? "";
}

export const ckflowRouter = createTRPCRouter({
	initiateCheckout: publicProcedure
		.input(feCreateCheckoutFlowPayloadModel)
		.mutation(async ({ input, ctx }) => {
			const flowId = nanoid();
			const ipAddress = getIPFromHeaders(ctx.headers);
			const userAgent = ctx.headers.get("user-agent") ?? "";
			return getCKUseCases().createFlow({
				domain: input.domain,
				refOIds: input.refOIds,
				productId: input.productId,
				ipAddress,
				userAgent,
				initialUrl: "",
				flowId,
				provider: "kiwi",
			});
		}),

	getFlowInfo: publicProcedure
		.input(z.object({ flowId: z.string() }))
		.query(async ({ input }) => {
			return getCKUseCases().getFlowInfo(input.flowId);
		}),

	updateFlowState: publicProcedure
		.input(z.object({ flowId: z.string(), payload: flowInfoModel }))
		.mutation(async ({ input }) => {
			return getCKUseCases().updateFlowState(input.flowId, input.payload);
		}),

	syncPersonalInfo: publicProcedure
		.input(
			z.object({
				flowId: z.string(),
				personalInfo: z.object({}).passthrough(),
			}),
		)
		.mutation(async ({ input }) => {
			return getCKUseCases().syncPersonalInfo(
				input.flowId,
				input.personalInfo as CustomerInfoModel,
			);
		}),

	syncPaymentInfo: publicProcedure
		.input(
			z.object({
				flowId: z.string(),
				paymentInfo: z.object({}).passthrough(),
			}),
		)
		.mutation(async ({ input }) => {
			return getCKUseCases().syncPaymentInfo(
				input.flowId,
				input.paymentInfo as PaymentInfoPayload,
			);
		}),

	ping: publicProcedure
		.input(z.object({ flowId: z.string() }))
		.mutation(async ({ input }) => {
			return getCKUseCases().ping(input.flowId);
		}),

	executePrePaymentStep: publicProcedure
		.input(
			z.object({
				flowId: z.string(),
				payload: z.object({
					initialUrl: z.string(),
					personalInfo: customerInfoModel.optional(),
				}),
			}),
		)
		.mutation(async ({ input }) => {
			return getCKUseCases().executePrePaymentStep(
				input.flowId,
				input.payload as PrePaymentFlowStepPayload,
			);
		}),

	executePaymentStep: publicProcedure
		.input(
			z.object({
				flowId: z.string(),
				payload: z.object({
					personalInfo: customerInfoModel.optional(),
					paymentInfo: paymentInfoPayloadModel.optional(),
				}),
			}),
		)
		.mutation(async ({ input }) => {
			return getCKUseCases().executePaymentStep(
				input.flowId,
				input.payload as PaymentFlowStepPayload,
			);
		}),

	goBackToInitialStep: publicProcedure
		.input(z.object({ flowId: z.string() }))
		.mutation(async ({ input }) => {
			return getCKUseCases().goBackToInitialStep(input.flowId);
		}),

	cleanupFlow: publicProcedure
		.input(
			z.object({
				flowId: z.string(),
				other: z.object({
					sessionOutcome: z.nativeEnum(SessionOutcome),
					checkoutStep: z.nativeEnum(CheckoutStep),
				}),
			}),
		)
		.mutation(async ({ input }) => {
			return getCKUseCases().cleanupFlow(input.flowId, input.other);
		}),
});
