import {
  createCheckout,
  getCustomer,
  getOrder,
} from "@lemonsqueezy/lemonsqueezy.js";

import { HttpStatusCode } from "@turbostarter/shared/constants";
import { logger } from "@turbostarter/shared/logger";
import { HttpException } from "@turbostarter/shared/utils";

import { config } from "../../config";
import { getCustomerByCustomerId, updateCustomer } from "../../lib/customer";
import { getCustomerByUserId } from "../../server";
import { getHighestDiscountForPrice } from "../../utils";

import { createOrRetrieveCustomer } from "./customer";
import { env } from "./env";
import { toCheckoutBillingStatus } from "./mappers/to-billing-status";

import type { BillingProviderStrategy } from "../types";

export const checkout: BillingProviderStrategy["checkout"] = async ({
  user,
  price: { id },
  redirect,
}) => {
  try {
    const plan = config.plans.find((plan) =>
      plan.prices.some((p) => p.id === id),
    );

    const price = plan?.prices.find((p) => p.id === id);

    if (!price || !plan) {
      throw new HttpException(HttpStatusCode.NOT_FOUND, {
        code: "billing:error.priceNotFound",
      });
    }

    const customer = await createOrRetrieveCustomer({
      email: user.email,
      id: user.id,
    });

    const discount = getHighestDiscountForPrice(price, config.discounts);

    const session = await createCheckout(env.LEMON_SQUEEZY_STORE_ID, id, {
      checkoutData: {
        email: customer.attributes.email,
        name: customer.attributes.name,
        custom: {
          user_id: user.id,
        },
        ...(discount && { discountCode: discount.code }),
      },
      productOptions: {
        enabledVariants: [Number(id)],
        redirectUrl: redirect.success,
      },
    });

    return { url: session.data?.data.attributes.url ?? null };
  } catch (e) {
    logger.error(e);
    throw new HttpException(HttpStatusCode.INTERNAL_SERVER_ERROR, {
      code: "billing:error.checkout",
    });
  }
};

export const getBillingPortal: BillingProviderStrategy["getBillingPortal"] =
  async ({ user }) => {
    const defaultUrl = `https://${env.LEMON_SQUEEZY_STORE_ID}.lemonsqueezy.com/billing`;

    try {
      const customer = await getCustomerByUserId(user.id);

      if (!customer) {
        return {
          url: defaultUrl,
        };
      }

      const lemonCustomer = await getCustomer(customer.customerId);

      const url = lemonCustomer.data?.data.attributes.urls.customer_portal;

      return { url: url ?? defaultUrl };
    } catch (e) {
      logger.error(e);
      throw new HttpException(HttpStatusCode.INTERNAL_SERVER_ERROR, {
        code: "billing:error.portal",
      });
    }
  };

export const checkoutStatusChangeHandler = async ({ id }: { id: string }) => {
  const { data } = await getOrder(id);

  const order = data?.data;

  if (!order) {
    throw new HttpException(HttpStatusCode.NOT_FOUND, {
      code: "billing:error.orderNotFound",
    });
  }

  const customer = await getCustomerByCustomerId(
    order.attributes.customer_id.toString(),
  );

  if (!customer) {
    throw new HttpException(HttpStatusCode.NOT_FOUND, {
      code: "billing:error.customerNotFound",
    });
  }

  const priceId = order.attributes.first_order_item.variant_id.toString();
  const plan = config.plans.find((p) => p.prices.find((x) => x.id === priceId));

  await updateCustomer(customer.userId, {
    status: toCheckoutBillingStatus(order.attributes.status),
    ...(plan && { plan: plan.id }),
  });

  logger.info(
    `✅ Checkout status changed for user ${customer.userId} to ${order.attributes.status}`,
  );
};
