import Stripe from 'stripe';
import { PlanDao } from "../dao/plan.dao";
import { PaymentDao } from "../dao/payment.dao";
import { LanguageService } from "../services/language.service";
import { Common } from "../../utils/common";
import { AppError } from "../../utils/errors";
import { PAYMENT } from "../config/constants";

const stripe = process.env.STRIPE_SECRET_KEY!?new Stripe(process.env.STRIPE_SECRET_KEY!):new Stripe('unconfigured');

export class StripeService {

    createProduct = async (name: string): Promise<string | null> => {
        try {
            const product = await stripe.products.create({ name: name });

            if (product) {
                return product.id
            } else {
                throw new AppError(400, 'STRIPE_PRODUCT_CREATION_ERROR', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    createPrice = async (externalProductId: string, amount: number, currency: string, interval: 'day' | 'week' | 'month' | 'year', intervalCount: number = 1) => {
        try {
            const centAmount = Math.round(amount * 100);
            const price = await stripe.prices.create({
                currency: currency, unit_amount: centAmount,
                recurring: { interval: interval, interval_count: intervalCount },
                product: externalProductId,
                tax_behavior: (process.env.STRIPE_TAX_BEHAVIOR as Stripe.PriceCreateParams.TaxBehavior | undefined)
            });

            if (price) {
                return price.id;
            } else {
                throw new AppError(400, 'STRIPE_PRICE_CREATION_ERROR', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // create stripe customer
    createCustomer = async (email: string) => {
        try {
            const stripeCustomer = await stripe.customers.create({ email });
            if (stripeCustomer?.id) {
                return stripeCustomer.id;
            } else {
                throw new AppError(400, 'STRIPE_CUSTOMER_ERROR', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

        // fetch payment methods
    attachPaymentMethodToCustomer = async (paymentMethodId: string, customerId: string) => {
        try {
            const paymentMethod = await stripe.paymentMethods.attach(
                paymentMethodId, 
                { 
                    customer: customerId 
                }
            );

            if (paymentMethod.id) {
                return true;
            } else {
                throw new AppError(400, 'UNABLE_TO_CREATE_SECRET', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // remove payment method from customer
    removePaymentMethodToCustomer = async (paymentMethodId: string) => {
        try {
            const paymentMethod = await stripe.paymentMethods.detach(
                paymentMethodId
            );

            if (paymentMethod.id) {
                return true;
            } else {
                throw new AppError(400, 'UNABLE_TO_CREATE_SECRET', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // attaching the payment method to customer stripe
    setDefaultPaymentMethod = async (paymentMethodId: string, customerId: string) => {
        try {
            await stripe.customers.update(customerId, {
                invoice_settings: { default_payment_method: paymentMethodId }
            });
            return true;

        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // attaching the payment method to customer stripe
    listPaymentMethod = async (customerId: string) => {
        try {
            const paymentMethods = await stripe.customers.listPaymentMethods(
                customerId
            );
            return paymentMethods;

        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    createCoupon = async (points: number) => {
        try {
            const coupon = await stripe.coupons.create({
                duration: 'once',
                amount_off: points * 100,
            });

            return coupon.id;
        } catch (error) {
            console.log(error)
        }
    }

    // create subscription on stripe
    createSubscription = async (customerId: string, priceId: string, trial: number | null, metaData: Stripe.MetadataParam | undefined) => {
        try {
            const trialObject: { trial_end?: number } = {}
            if(trial) {
                trialObject["trial_end"] = trial
            }

            const subscription = await stripe.subscriptions.create({
                customer: customerId,
                items: [{ price: priceId }],
                payment_behavior: 'default_incomplete',
                expand: ['latest_invoice.confirmation_secret'],
                metadata: metaData,
                ...trialObject
                //discounts: [{ coupon: await this.createCoupon() }]
            });

            if (subscription.id) {
                return subscription;
            } else {
                throw new AppError(400, 'ERROR_CREATING_SUBSCRIPTION', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // create subscription on stripe
    updateSubscription = async (subscriptionId: string, options: {priceId?: string | undefined, points?: number | undefined, cancel?: boolean | undefined}) => {
        try {
            const subscription = await stripe.subscriptions.retrieve(subscriptionId);

            let object: any = {};
            if(options?.priceId) {
                object = {
                    items: [
                        {
                            id: subscription.items.data[0].id,
                            price: options.priceId,
                        },
                    ],
                    // Optional: invoice immediately for proration
                    proration_behavior: 'create_prorations'
                }
            } else if (options.points) {
                object = {
                    discounts: [
                        {
                            coupon: await this.createCoupon(options.points)
                        }
                    ]
                }
            } else if(options.cancel === true) {
                object = { 
                    cancel_at_period_end: true 
                }
            } else {
                throw new AppError(400, 'ERROR_UPDATING_SUBSCRIPTION', {});
            }

            const updatedSubscription = await stripe.subscriptions.update(subscriptionId, object);

            if (subscription.id) {
                return updatedSubscription;
            } else {
                throw new AppError(400, 'ERROR_CREATING_SUBSCRIPTION', {});
            }
        } catch (err) {
            console.log(err)
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // cancel subscription on stripe
    createPaymentIntent = async (amount: number, currency: string, customerId: string, metaData: Stripe.MetadataParam | undefined) => {
        try {
            const centAmount = Math.round(amount * 100);
            const paymentIntent = await stripe.paymentIntents.create({
                amount: centAmount,
                currency: currency,
                automatic_payment_methods: {
                    enabled: true,
                },
                customer: customerId,
                metadata: metaData
                //payment_method: paymentMethodId
            });

            if (paymentIntent.id) {
                return paymentIntent;
            } else {
                throw new AppError(400, 'ERROR_GENERATING_PAYMENT_INTENT', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }

    // Create PaymentIntent
    createWalletIntent = async (amount: number, currency: string): Promise<ClientSecret> => {
        try {
            const paymentIntent = await stripe.paymentIntents.create({
                amount: amount * 100,
                currency: currency,
                payment_method_types: ['card'], // Apple Pay & Google Pay use 'card'
            });
            if (paymentIntent && paymentIntent.client_secret) {
                return { clientSecret: paymentIntent.client_secret };
            } else {
                throw new AppError(400, 'UNABLE_TO_CREATE_SECRET', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_IN_SERVICE', err);
        }
    }
}
