import Plan from '../models/Plan';
import Subscription from '../models/Subscription';
import { SubscriptionPeriod } from '../models/SubscriptionPeriod';
import User from '../models/User';
import EmailService from './EmailService';

interface SubscribeData {
  userId: string;
  planId: string;
  billingCycle?: string;
}

interface UpgradeData {
  userId: string;
  planId: string;
  billingCycle?: string;
}

export class SubscriptionService {
  /**
   * Create a new subscription
   */
  async subscribe(data: SubscribeData) {
    const { userId, planId, billingCycle } = data;

    if (!userId || !planId) {
      throw new Error('Please provide user ID and plan ID');
    }

    const user = await User.findById(userId);
    if (!user) {
      throw new Error('User not found');
    }

    const plan = await Plan.findById(planId);
    if (!plan) {
      throw new Error('Plan not found');
    }

    // Calculate end date based on plan
    const startDate = new Date();
    const endDate = new Date();

    if (billingCycle === SubscriptionPeriod.ANNUAL) {
      endDate.setFullYear(endDate.getFullYear() + 1);
    } else if (billingCycle === SubscriptionPeriod.SIX_MONTH) {
      endDate.setMonth(endDate.getMonth() + 6);
    } else if (billingCycle === SubscriptionPeriod.FREELY) {
      endDate.setDate(endDate.getDate() + 2); // 48 hours
    } else {
      endDate.setMonth(endDate.getMonth() + 1);
    }

    const newSubscription = new Subscription({
      userId: user._id,
      planId: planId,
      startDate,
      endDate,
      status: 'Active',
    });

    await newSubscription.save();

    // Send confirmation email
    try {
      await EmailService.sendSubscriptionConfirmationEmail(user.email, user.firstName, plan.title, user.language || 'en');
    } catch (emailError: any) {
      console.error('Failed to send subscription confirmation email:', emailError);
    }

    return newSubscription;
  }

  /**
   * Upgrade existing subscription
   */
  async upgrade(data: UpgradeData) {
    const { userId, planId, billingCycle } = data;

    if (!userId || !planId) {
      throw new Error('Please provide user ID and plan ID');
    }

    const user = await User.findById(userId);
    if (!user) {
      throw new Error('User not found');
    }

    const plan = await Plan.findById(planId);
    if (!plan) {
      throw new Error('Plan not found');
    }

    // Calculate end date based on plan
    const startDate = new Date();
    const endDate = new Date();

    if (billingCycle === SubscriptionPeriod.ANNUAL) {
      endDate.setFullYear(endDate.getFullYear() + 1);
    } else if (billingCycle === SubscriptionPeriod.SIX_MONTH) {
      endDate.setMonth(endDate.getMonth() + 6);
    } else if (billingCycle === SubscriptionPeriod.FREELY) {
      endDate.setDate(endDate.getDate() + 2); // 48 hours
    } else {
      endDate.setMonth(endDate.getMonth() + 1);
    }

    // Deactivate old active subscriptions
    await Subscription.updateMany(
      { userId: user._id, status: 'Active' },
      { status: 'Cancelled' }
    );

    const newSubscription = new Subscription({
      userId: user._id,
      planId: planId,
      startDate,
      endDate,
      status: 'Active',
      autoRenew: true,
    });

    await newSubscription.save();

    // Update user status
    user.isActive = true;
    await user.save();

    // Send confirmation email
    try {
      await EmailService.sendSubscriptionConfirmationEmail(user.email, user.firstName, plan.title, user.language || 'en');
    } catch (emailError: any) {
      console.error('Failed to send subscription confirmation email:', emailError);
    }

    return newSubscription;
  }

  /**
   * Get user's active subscriptions
   */
  async getActiveSubscription(userId: string) {
    if (!userId) {
      throw new Error('User ID is required');
    }

    const user = await User.findById(userId);
    if (!user) {
      throw new Error('User not found');
    }

    // If secondary account, check owner's subscription
    const subscriptionUserId = user.ownerId || user._id;

    const subscriptions = await Subscription.find({
      userId: subscriptionUserId,
      status: 'Active',
      endDate: { $gt: new Date() }
    }).sort({ endDate: -1 }).populate('planId');

    return subscriptions;
  }

  /**
   * Get subscription details by ID
   */
  async getSubscriptionById(subscriptionId: string) {
    if (!subscriptionId) {
      throw new Error('Subscription ID is required');
    }

    const subscription = await Subscription.findById(subscriptionId).populate('planId');
    if (!subscription) {
      throw new Error('Subscription not found');
    }

    return subscription;
  }

  /**
   * Cancel subscription
   */
  async cancelSubscription(subscriptionId: string) {
    if (!subscriptionId) {
      throw new Error('Subscription ID is required');
    }

    const subscription = await Subscription.findByIdAndUpdate(
      subscriptionId,
      { status: 'Cancelled' },
      { new: true }
    );

    if (!subscription) {
      throw new Error('Subscription not found');
    }

    return subscription;
  }

  /**
   * Cancel current user's active subscription
   */
  async cancelMyActiveSubscription(userId: string, subscriptionId?: string) {
    if (!userId) {
      throw new Error('User ID is required');
    }

    const user = await User.findById(userId);
    if (!user) {
      throw new Error('User not found');
    }

    const subscriptionUserId = user.ownerId || user._id;

    const activeSubscriptions = await Subscription.find({
      userId: subscriptionUserId,
      status: 'Active',
      endDate: { $gt: new Date() }
    }).sort({ endDate: -1 });

    if (!activeSubscriptions.length) {
      throw new Error('No active subscription found');
    }

    let target = activeSubscriptions[0];
    if (subscriptionId) {
      const matched = activeSubscriptions.find((sub) => sub._id.toString() === subscriptionId);
      if (!matched) {
        throw new Error('Subscription not found');
      }
      target = matched;
    }

    const cancelled = await Subscription.findByIdAndUpdate(
      target._id,
      { status: 'Cancelled', autoRenew: false },
      { new: true }
    ).populate('planId');

    if (!cancelled) {
      throw new Error('Subscription not found');
    }

    return cancelled;
  }
}

export default new SubscriptionService();
