import { stripe } from '@/lib/stripe';
import { prisma } from '@/lib/db';
import Stripe from 'stripe';

export type PlanType = 'starter' | 'professional' | 'enterprise';

export interface PlanDetails {
  type: PlanType;
  name: string;
  nameAr: string;
  monthlyPrice: number;
  stripePriceId: string;
  features: string[];
  featuresAr: string[];
  setupFee?: number;
}

export interface CurrentSubscription {
  id: string;
  userId: string;
  stripeSubscriptionId: string;
  stripeCustomerId: string;
  stripePriceId: string;
  planType: PlanType;
  status: string;
  currentPeriodStart: Date;
  currentPeriodEnd: Date;
  cancelAtPeriodEnd: boolean;
  amount: number;
  currency: string;
  daysRemaining: number;
  daysInPeriod: number;
  daysUsed: number;
}

export interface ProrationCalculation {
  currentPlan: PlanDetails;
  newPlan: PlanDetails;
  daysRemaining: number;
  daysInPeriod: number;
  creditFromCurrentPlan: number;
  chargeForNewPlan: number;
  immediateCharge: number;
  nextBillingAmount: number;
  isUpgrade: boolean;
}

// Available plans configuration
export const AVAILABLE_PLANS: Record<PlanType, PlanDetails> = {
  starter: {
    type: 'starter',
    name: 'Starter',
    nameAr: 'الباقة الأساسية',
    monthlyPrice: 99,
    stripePriceId: process.env.STRIPE_PRICE_ID_STARTER || '',
    setupFee: 50,
    features: [
      '1 WhatsApp Business Account',
      'Up to 1,000 messages/month',
      'Basic appointment scheduling',
      'Email support'
    ],
    featuresAr: [
      'حساب واتساب للأعمال واحد',
      'حتى 1,000 رسالة شهريًا',
      'جدولة المواعيد الأساسية',
      'دعم عبر البريد الإلكتروني'
    ]
  },
  professional: {
    type: 'professional',
    name: 'Professional',
    nameAr: 'الباقة الاحترافية',
    monthlyPrice: 299,
    stripePriceId: process.env.STRIPE_PRICE_ID_PROFESSIONAL || '',
    setupFee: 50,
    features: [
      '3 WhatsApp Business Accounts',
      'Up to 10,000 messages/month',
      'Advanced scheduling + reminders',
      'Analytics dashboard',
      'Priority support'
    ],
    featuresAr: [
      '3 حسابات واتساب للأعمال',
      'حتى 10,000 رسالة شهريًا',
      'جدولة متقدمة + تذكيرات',
      'لوحة التحليلات',
      'دعم ذو أولوية'
    ]
  },
  enterprise: {
    type: 'enterprise',
    name: 'Enterprise',
    nameAr: 'باقة المؤسسات',
    monthlyPrice: 999,
    stripePriceId: process.env.STRIPE_PRICE_ID_ENTERPRISE || '',
    setupFee: 50,
    features: [
      'Unlimited WhatsApp accounts',
      'Unlimited messages',
      'Custom integrations',
      'Dedicated account manager',
      'SLA guarantee',
      '24/7 support'
    ],
    featuresAr: [
      'حسابات واتساب غير محدودة',
      'رسائل غير محدودة',
      'تكامل مخصص',
      'مدير حساب مخصص',
      'ضمان مستوى الخدمة',
      'دعم على مدار الساعة'
    ]
  }
};

/**
 * Get current user's active subscription
 */
export async function getCurrentUserSubscription(
  userId: string,
  stripeCustomerId: string
): Promise<CurrentSubscription | null> {
  const subscription = await prisma.subscriptions.findFirst({
    where: {
      stripeCustomerId,
      status: { in: ['active', 'trialing'] },
    },
    orderBy: { createdAt: 'desc' },
  });

  if (!subscription) {
    return null;
  }

  const currentPeriodStart = new Date(subscription.currentPeriodStart);
  const currentPeriodEnd = new Date(subscription.currentPeriodEnd);
  const today = new Date();

  const daysInPeriod = Math.ceil(
    (currentPeriodEnd.getTime() - currentPeriodStart.getTime()) / (1000 * 60 * 60 * 24)
  );
  const daysRemaining = Math.ceil(
    (currentPeriodEnd.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)
  );
  const daysUsed = daysInPeriod - daysRemaining;

  return {
    id: subscription.id,
    userId: subscription.userId,
    stripeSubscriptionId: subscription.stripeSubscriptionId,
    stripeCustomerId: subscription.stripeCustomerId,
    stripePriceId: subscription.stripePriceId,
    planType: subscription.planType as PlanType,
    status: subscription.status,
    currentPeriodStart,
    currentPeriodEnd,
    cancelAtPeriodEnd: subscription.cancelAtPeriodEnd || false,
    amount: subscription.amount || 0,
    currency: subscription.currency || 'usd',
    daysRemaining: Math.max(0, daysRemaining),
    daysInPeriod,
    daysUsed: Math.max(0, daysUsed)
  };
}

/**
 * Get available plans for upgrade/downgrade (excluding setup fees)
 */
export async function getAvailablePlans(
  currentPlanType: PlanType,
  isExistingCustomer: boolean = true
): Promise<{
  upgrades: PlanDetails[];
  downgrades: PlanDetails[];
  current: PlanDetails;
}> {
  const planOrder: PlanType[] = ['starter', 'professional', 'enterprise'];
  const currentIndex = planOrder.indexOf(currentPlanType);

  const upgrades = planOrder
    .slice(currentIndex + 1)
    .map(type => {
      const plan = { ...AVAILABLE_PLANS[type] };
      // Remove setup fee for existing customers
      if (isExistingCustomer) {
        delete plan.setupFee;
      }
      return plan;
    });

  const downgrades = planOrder
    .slice(0, currentIndex)
    .map(type => {
      const plan = { ...AVAILABLE_PLANS[type] };
      // Remove setup fee for existing customers
      if (isExistingCustomer) {
        delete plan.setupFee;
      }
      return plan;
    });

  return {
    upgrades,
    downgrades,
    current: AVAILABLE_PLANS[currentPlanType]
  };
}

/**
 * Calculate proration for plan change using our formula
 * Note: In production, use Stripe's retrieveUpcoming for accuracy
 */
export function calculateProration(
  currentSubscription: CurrentSubscription,
  newPlan: PlanDetails
): ProrationCalculation {
  const { daysRemaining, daysInPeriod, amount: currentAmount } = currentSubscription;
  const newAmount = newPlan.monthlyPrice;

  // Calculate daily rates
  const dailyRateCurrentPlan = currentAmount / daysInPeriod;
  const dailyRateNewPlan = newAmount / daysInPeriod;

  // Credit from unused portion of current plan
  const creditFromCurrentPlan = dailyRateCurrentPlan * daysRemaining;

  // Charge for remaining period on new plan
  const chargeForNewPlan = dailyRateNewPlan * daysRemaining;

  // Net immediate charge (can be negative for downgrades)
  const immediateCharge = chargeForNewPlan - creditFromCurrentPlan;

  const isUpgrade = newAmount > currentAmount;

  return {
    currentPlan: AVAILABLE_PLANS[currentSubscription.planType],
    newPlan,
    daysRemaining,
    daysInPeriod,
    creditFromCurrentPlan: Math.round(creditFromCurrentPlan * 100) / 100,
    chargeForNewPlan: Math.round(chargeForNewPlan * 100) / 100,
    immediateCharge: Math.round(immediateCharge * 100) / 100,
    nextBillingAmount: newAmount,
    isUpgrade
  };
}

/**
 * Get proration preview from Stripe (most accurate)
 */
export async function getStripeProrationPreview(
  stripeCustomerId: string,
  subscriptionId: string,
  subscriptionItemId: string,
  newPriceId: string
): Promise<{
  immediateCharge: number;
  nextBillingAmount: number;
  prorationDate: Date;
}> {
  const upcomingInvoice = await stripe.invoices.retrieveUpcoming({
    customer: stripeCustomerId,
    subscription: subscriptionId,
    subscription_items: [
      {
        id: subscriptionItemId,
        price: newPriceId,
      },
    ],
    subscription_proration_behavior: 'create_prorations',
  });

  const immediateCharge = upcomingInvoice.amount_due / 100;
  const nextBillingAmount = (upcomingInvoice.total / 100);

  return {
    immediateCharge,
    nextBillingAmount,
    prorationDate: new Date(upcomingInvoice.period_start * 1000)
  };
}

/**
 * Get billing history for a user
 */
export async function getBillingHistory(
  userId: string,
  limit: number = 10
): Promise<any[]> {
  try {
    const history = await prisma.billing_history.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });

    return history || [];
  } catch (error) {
    console.error('Error fetching billing history:', error);
    return [];
  }
}

/**
 * Check if user has already paid setup fee
 */
export async function hasUserPaidSetupFee(userId: string): Promise<boolean> {
  try {
    const record = await prisma.billing_history.findFirst({
      where: {
        userId,
        billingReason: 'subscription_create',
      },
      select: { id: true },
    });

    return !!record;
  } catch (error) {
    console.error('Error checking setup fee:', error);
    return false;
  }
}

/**
 * Update subscription plan in Stripe and database
 */
export async function updateSubscriptionPlan(
  userId: string,
  subscriptionId: string,
  newPriceId: string,
  prorationBehavior: 'create_prorations' | 'none' = 'create_prorations'
): Promise<{ success: boolean; error?: string; subscription?: Stripe.Subscription }> {
  try {
    // Get the subscription from Stripe
    const subscription = await stripe.subscriptions.retrieve(subscriptionId);

    if (!subscription.items.data[0]) {
      return { success: false, error: 'No subscription items found' };
    }

    // Update the subscription
    const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
      items: [
        {
          id: subscription.items.data[0].id,
          price: newPriceId,
        },
      ],
      proration_behavior: prorationBehavior,
    });

    // Update in database (webhook will also update, but we do it here for immediate consistency)
    const newPlanType = getPlanTypeFromPriceId(newPriceId);

    await prisma.subscriptions.updateMany({
      where: { stripeSubscriptionId: subscriptionId },
      data: {
        stripePriceId: newPriceId,
        planType: newPlanType,
        updatedAt: new Date(),
      },
    });

    return { success: true, subscription: updatedSubscription };
  } catch (error: any) {
    console.error('Error updating subscription:', error);
    return { success: false, error: error.message };
  }
}

/**
 * Helper to determine plan type from Stripe price ID
 */
function getPlanTypeFromPriceId(priceId: string): PlanType {
  if (priceId === process.env.STRIPE_PRICE_ID_STARTER) return 'starter';
  if (priceId === process.env.STRIPE_PRICE_ID_PROFESSIONAL) return 'professional';
  if (priceId === process.env.STRIPE_PRICE_ID_ENTERPRISE) return 'enterprise';
  return 'starter'; // Default fallback
}
