import Stripe from "stripe";
import { env } from "~/env.mjs";
import { TRPCError } from "@trpc/server";
import PaymentStatusEnum from "~/schemas/public/PaymentStatusEnum";
import { db } from "~/server/db";
import type { Payments, PaymentsId } from "~/schemas/public/Payments";
import OrderTypeEnum from "~/schemas/public/OrderTypeEnum";
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
import { NewMail } from "~/server/services/mailer";
import { getUser } from "~/server/services/user.service";

const stripeApi = new Stripe(env.STRIPE_SECRET_KEY);

export const createIntentHandler = async ({
  paymentId,
}: {
  paymentId: PaymentsId;
}) => {
  try {
    const payment = await db
      .selectFrom("payments")
      .selectAll("payments")
      .innerJoin("ordini", "ordini.ordine_id", "payments.ordine_id")
      .innerJoin("prezziario", "prezziario.idprezziario", "ordini.packid")
      .select(["prezziario.nome_it", "prezziario.desc_it"])
      .where("id", "=", paymentId)
      .executeTakeFirstOrThrow();

    const paymentIntent = await stripeApi.paymentIntents.create({
      amount: payment.amount_cent,
      description: payment.nome_it,
      currency: "eur",
      //payment_method_configuration: "pmc_1P4NfjILe4KoQRqXYChFCTFj",
      automatic_payment_methods: {
        enabled: true,
      },
      metadata: {
        userId: payment.userid,
        servizioId: payment.servizio_id,
        paymentId,
      },
    });

    return {
      clientSecret: paymentIntent.client_secret,
      titolo: payment.nome_it,
      prezzo: payment.amount_cent,
      descrizione: payment.desc_it,
    };
  } catch (error) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Error creating payment intent: " + (error as Error).message,
    });
  }
};

export const whIntentCreatedHandler = async ({
  pIntentId,
  paymentId,
}: {
  pIntentId: Payments["intent_id"];
  paymentId: PaymentsId;
}) => {
  return await db
    .updateTable("payments")
    .set({ intent_id: pIntentId, paymentstatus: PaymentStatusEnum.processing })
    .where("id", "=", paymentId)
    .returning("id")
    .execute();
};

export const whIntentSucceededHandler = async ({
  pIntentId,
  paymentId,
  pm_id,
}: {
  pIntentId: Payments["intent_id"];
  paymentId: PaymentsId;
  pm_id: string;
}) => {
  try {
    const paymentMethod = await stripeApi.paymentMethods.retrieve(pm_id);

    await db.transaction().execute(async (trx) => {
      const payment = await trx
        .updateTable("payments")
        .set({
          paymentstatus: PaymentStatusEnum.success,
          paid_at: new Date(),
          paymentmethod: paymentMethod.type,
        })
        .where("intent_id", "=", pIntentId)
        .where("payments.id", "=", paymentId)
        .returning(["servizio_id", "ordine_id"])
        .executeTakeFirstOrThrow();

      const ordine = await trx
        .selectFrom("ordini")
        .selectAll("ordini")
        .where("ordine_id", "=", payment.ordine_id)
        .executeTakeFirstOrThrow();

      await trx
        .updateTable("ordini")
        .where("ordine_id", "=", payment.ordine_id)
        .set({
          isActive: true,
        })
        .execute();

      const servizio = await trx
        .selectFrom("servizio")
        .select("servizio.tipologia")
        .where("servizio_id", "=", payment.servizio_id)
        .executeTakeFirstOrThrow();

      const utente = await getUser({
        db: trx,
        userId: ordine.userid,
      });

      switch (ordine.type) {
        case OrderTypeEnum.Acconto:
          await trx
            .updateTable("servizio")
            .where("servizio_id", "=", payment.servizio_id)
            .set({
              decorrenza: new Date(),
              isOkAcconto: true,
            })
            .execute();

          await NewMail({
            userId: utente.id,
            mailType: "generic",
            to: utente.email,
            subject: "Pagamento Confermato - Acconto Infoalloggi.it",

            props: {
              title: "Pagamento Confermato ",
              noreply: true,
              testo: `Il pagamento dell'acconto per il servizio ${ordine.packid} è stato confermato.`,
              link: {
                href: `${env.NEXT_PUBLIC_BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
                label: "Vai alla ricevuta",
              },
            },
          });
          break;

        case OrderTypeEnum.Saldo:
          await trx
            .updateTable("servizio")
            .where("servizio_id", "=", payment.servizio_id)
            .set({
              isOkSaldo: true,
              isOkConsulenza:
                servizio.tipologia == TipologiaPosizioneEnum.Transitorio
                  ? true
                  : false,
            })
            .execute();
          await NewMail({
            userId: utente.id,
            mailType: "generic",
            to: utente.email,
            subject: "Pagamento Confermato - Saldo Infoalloggi.it",
            props: {
              title: "Pagamento Confermato ",
              noreply: true,
              testo: `Il pagamento del saldo per il servizio ${ordine.packid} è stato confermato.`,
              link: {
                href: `${env.NEXT_PUBLIC_BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
                label: "Vai alla ricevuta",
              },
            },
          });
          break;
        case OrderTypeEnum.Consulenza:
          await trx
            .updateTable("servizio")
            .where("servizio_id", "=", payment.servizio_id)
            .set({
              isOkConsulenza: true,
            })
            .execute();
          await NewMail({
            userId: utente.id,
            mailType: "generic",
            to: utente.email,
            subject: "Pagamento Confermato - Consulenza Infoalloggi.it",
            props: {
              title: "Pagamento Confermato ",
              noreply: true,
              testo: `Il pagamento per la consulenza è stato confermato.`,
              link: {
                href: `${env.NEXT_PUBLIC_BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
                label: "Vai alla ricevuta",
              },
            },
          });
          break;
        case OrderTypeEnum.Altro:
          // TODO: Handle other types
          await NewMail({
            userId: utente.id,
            mailType: "pagamentoConferma",
            to: utente.email,
            subject: "Pagamento Confermato",
            props: {
              receiptHref: `${env.NEXT_PUBLIC_BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
            },
          });
          break;
      }
    });
    return true;
  } catch (error) {
    throw new TRPCError({
      code: "INTERNAL_SERVER_ERROR",
      message: "Error updating payment intent: " + (error as Error).message,
    });
  }
};

export const whIntentFailedHandler = async ({
  pIntentId,
}: {
  pIntentId: Payments["intent_id"];
}) => {
  const userId = await db
    .updateTable("payments")
    .set({
      paymentstatus: PaymentStatusEnum.failed,
    })
    .returning("userid")
    .where("intent_id", "=", pIntentId)
    .execute();

  if (userId[0]) {
    const utente = await getUser({
      db,
      userId: userId[0].userid,
    });

    await NewMail({
      userId: utente.id,
      mailType: "pagamentoErrore",
      to: utente.email,
      subject: "Pagamento Fallito",
    });
  }
  return true;
};
