import { BillingService } from "../../../Services/BillingService";
import {
  ChangePlan,
  CouponData,
  CustomerData,
  MeteredSubscription,
  Subscription,
} from "../../TestingUtils/Services/Types";
import { faker } from "@faker-js/faker";
import SubscriptionPlan from "Common/Types/Billing/SubscriptionPlan";
import Email from "Common/Types/Email";
import ProductType from "Common/Types/MeteredPlan/ProductType";
import ObjectID from "Common/Types/ObjectID";
import { Stripe } from "stripe";

/// @dev consider modifyfing the EnvirontmentConfig to use functions instead of constants so that we can mock them

type MockIsBillingEnabledFunction = (value: boolean) => BillingService;

const mockIsBillingEnabled: MockIsBillingEnabledFunction = (
  value: boolean,
): BillingService => {
  jest.resetModules();
  jest.doMock("../../../BillingConfig", () => {
    return {
      IsBillingEnabled: value,
    };
  });
  const { BillingService } = require("../../../Services/BillingService");
  return new BillingService();
};

type GetStripeCustomerFunction = (id?: string) => Stripe.Customer;

const getStripeCustomer: GetStripeCustomerFunction = (
  id?: string,
): Stripe.Customer => {
  id = id || faker.datatype.uuid();
  return {
    id,
    object: "customer",
    balance: faker.datatype.number(),
    created: 1,
    default_source: null,
    description: null,
    email: null,
    invoice_settings: {
      custom_fields: null,
      default_payment_method: null,
      footer: null,
      rendering_options: null,
    },
    livemode: true,
    metadata: {},
    shipping: null,
  };
};

type GetStripeSubscriptionFunction = () => Stripe.Subscription;

const getStripeSubscription: GetStripeSubscriptionFunction =
  (): Stripe.Subscription => {
    return {
      id: faker.datatype.uuid(),
      items: {
        data: [
          {
            id: faker.datatype.uuid(),
            // @ts-ignore
            price: {
              id: new BillingService().getMeteredPlanPriceId(
                ProductType.ActiveMonitoring,
              ),
            },
          },
        ],
      },
      status: "active",
      customer: getStripeCustomer(),
    };
  };

type GetSubscriptionPlanDataFunction = () => SubscriptionPlan;

const getSubscriptionPlanData: GetSubscriptionPlanDataFunction =
  (): SubscriptionPlan => {
    return new SubscriptionPlan(
      faker.datatype.uuid(), // monthlyPlanId
      faker.datatype.uuid(), // yearlyPlanId
      faker.commerce.productName(), // name
      faker.datatype.number(), // monthlySubscriptionAmountInUSD
      faker.datatype.number({ min: 1, max: 100 }), // yearlySubscriptionAmountInUSD
      faker.datatype.number({ min: 1, max: 100 }), // order
      faker.datatype.number({ min: 1, max: 100 }), // trial period days
    );
  };

type GetStripeInvoiceFunction = () => Stripe.Invoice;

const getStripeInvoice: GetStripeInvoiceFunction = (): Stripe.Invoice => {
  // @ts-ignore
  return {
    id: faker.datatype.uuid(),
    amount_due: faker.datatype.number(),
    currency: "usd",
    customer: faker.datatype.uuid(),
    subscription: faker.datatype.uuid(),
    status: "paid",
  };
};

type GetCustomerDataFunction = (id?: ObjectID) => CustomerData;

const getCustomerData: GetCustomerDataFunction = (
  id?: ObjectID,
): CustomerData => {
  return {
    id: id || new ObjectID("customer_id"),
    name: "John Doe",
    email: new Email("test@example.com"),
  };
};

type GetSubscriptionDataFunction = (id?: ObjectID) => Subscription;

const getSubscriptionData: GetSubscriptionDataFunction = (
  id?: ObjectID,
): Subscription => {
  return {
    projectId: id || new ObjectID("project_id"),
    customerId: "cust_123",
    serverMeteredPlans: [],
    trialDate: new Date(),
  };
};

type GetMeteredSubscriptionFunction = (
  subscriptionPlan: SubscriptionPlan,
  id?: ObjectID,
) => MeteredSubscription;

const getMeteredSubscription: GetMeteredSubscriptionFunction = (
  subscriptionPlan: SubscriptionPlan,
  id?: ObjectID,
): MeteredSubscription => {
  return {
    projectId: id || new ObjectID("project_id"),
    customerId: "cust_123",
    serverMeteredPlans: [],
    plan: subscriptionPlan,
    quantity: 1,
    isYearly: false,
    trial: true,
  };
};

type GetChangePlanDataFunction = (
  subscriptionPlan: SubscriptionPlan,
  id?: ObjectID,
) => ChangePlan;

const getChangePlanData: GetChangePlanDataFunction = (
  subscriptionPlan: SubscriptionPlan,
  id?: ObjectID,
): ChangePlan => {
  return {
    projectId: id || new ObjectID("project_id"),
    subscriptionId: "sub_123",
    meteredSubscriptionId: "sub_456",
    serverMeteredPlans: [],
    newPlan: subscriptionPlan,
    quantity: 1,
    isYearly: false,
  };
};

type GetCouponDataFunction = () => CouponData;

const getCouponData: GetCouponDataFunction = (): CouponData => {
  return {
    name: "TESTCOUPON",
    metadata: { description: "Test coupon" },
    percentOff: 10,
    durationInMonths: 3,
    maxRedemptions: 100,
  };
};

export {
  mockIsBillingEnabled,
  getStripeCustomer,
  getStripeSubscription,
  getSubscriptionPlanData,
  getCustomerData,
  getSubscriptionData,
  getMeteredSubscription,
  getChangePlanData,
  getCouponData,
  getStripeInvoice,
};
