/**
 * @ai-summary Subscriptions API controller
 * @ai-context Handles subscription management API requests
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import { logger } from '../../../core/logging/logger';
import { SubscriptionsService } from '../domain/subscriptions.service';
import { SubscriptionsRepository } from '../data/subscriptions.repository';
import { StripeClient } from '../external/stripe/stripe.client';
import { pool } from '../../../core/config/database';

export class SubscriptionsController {
  private service: SubscriptionsService;

  constructor() {
    const repository = new SubscriptionsRepository(pool);
    const stripeClient = new StripeClient();
    this.service = new SubscriptionsService(repository, stripeClient, pool);
  }

  /**
   * GET /api/subscriptions - Get current subscription
   */
  async getSubscription(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      const subscription = await this.service.getSubscription(userId);

      if (!subscription) {
        reply.status(404).send({
          error: 'Subscription not found',
          message: 'No subscription exists for this user',
        });
        return;
      }

      reply.status(200).send(subscription);
    } catch (error: any) {
      logger.error('Failed to get subscription', {
        userId: (request as any).user?.sub,
        error: error.message,
      });
      reply.status(500).send({
        error: 'Failed to get subscription',
        message: error.message,
      });
    }
  }

  /**
   * GET /api/subscriptions/needs-vehicle-selection - Check if user needs vehicle selection
   */
  async checkNeedsVehicleSelection(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      const result = await this.service.checkNeedsVehicleSelection(userId);

      reply.status(200).send(result);
    } catch (error: any) {
      logger.error('Failed to check needs vehicle selection', {
        userId: (request as any).user?.sub,
        error: error.message,
      });
      reply.status(500).send({
        error: 'Failed to check needs vehicle selection',
        message: error.message,
      });
    }
  }

  /**
   * POST /api/subscriptions/checkout - Create Stripe checkout session
   */
  async createCheckout(
    request: FastifyRequest<{
      Body: {
        tier: 'pro' | 'enterprise';
        billingCycle: 'monthly' | 'yearly';
        paymentMethodId?: string;
      };
    }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;
      const email = (request as any).user.email;
      const { tier, billingCycle, paymentMethodId } = request.body;

      // Validate inputs
      if (!tier || !billingCycle) {
        reply.status(400).send({
          error: 'Missing required fields',
          message: 'tier and billingCycle are required',
        });
        return;
      }

      if (!['pro', 'enterprise'].includes(tier)) {
        reply.status(400).send({
          error: 'Invalid tier',
          message: 'tier must be "pro" or "enterprise"',
        });
        return;
      }

      if (!['monthly', 'yearly'].includes(billingCycle)) {
        reply.status(400).send({
          error: 'Invalid billing cycle',
          message: 'billingCycle must be "monthly" or "yearly"',
        });
        return;
      }

      // Create or get existing subscription
      let subscription = await this.service.getSubscription(userId);
      if (!subscription) {
        await this.service.createSubscription(userId, email);
        subscription = await this.service.getSubscription(userId);
      }

      if (!subscription) {
        reply.status(500).send({
          error: 'Failed to create subscription',
          message: 'Could not initialize subscription',
        });
        return;
      }

      // Upgrade subscription
      const updatedSubscription = await this.service.upgradeSubscription(
        userId,
        tier,
        billingCycle,
        paymentMethodId || ''
      );

      reply.status(200).send(updatedSubscription);
    } catch (error: any) {
      logger.error('Failed to create checkout', {
        userId: (request as any).user?.sub,
        error: error.message,
      });
      reply.status(500).send({
        error: 'Failed to create checkout',
        message: error.message,
      });
    }
  }

  /**
   * POST /api/subscriptions/cancel - Schedule cancellation
   */
  async cancelSubscription(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      const subscription = await this.service.cancelSubscription(userId);

      reply.status(200).send(subscription);
    } catch (error: any) {
      logger.error('Failed to cancel subscription', {
        userId: (request as any).user?.sub,
        error: error.message,
      });
      reply.status(500).send({
        error: 'Failed to cancel subscription',
        message: error.message,
      });
    }
  }

  /**
   * POST /api/subscriptions/reactivate - Cancel pending cancellation
   */
  async reactivateSubscription(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      const subscription = await this.service.reactivateSubscription(userId);

      reply.status(200).send(subscription);
    } catch (error: any) {
      logger.error('Failed to reactivate subscription', {
        userId: (request as any).user?.sub,
        error: error.message,
      });
      reply.status(500).send({
        error: 'Failed to reactivate subscription',
        message: error.message,
      });
    }
  }

  /**
   * PUT /api/subscriptions/payment-method - Update payment method
   */
  async updatePaymentMethod(
    request: FastifyRequest<{
      Body: {
        paymentMethodId: string;
      };
    }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;
      const { paymentMethodId } = request.body;

      // Validate input
      if (!paymentMethodId) {
        reply.status(400).send({
          error: 'Missing required field',
          message: 'paymentMethodId is required',
        });
        return;
      }

      // Get subscription
      const subscription = await this.service.getSubscription(userId);
      if (!subscription) {
        reply.status(404).send({
          error: 'Subscription not found',
          message: 'No subscription exists for this user',
        });
        return;
      }

      // Update payment method via Stripe
      const stripeClient = new StripeClient();
      await stripeClient.updatePaymentMethod(subscription.stripeCustomerId, paymentMethodId);

      reply.status(200).send({
        message: 'Payment method updated successfully',
      });
    } catch (error: any) {
      logger.error('Failed to update payment method', {
        userId: (request as any).user?.sub,
        error: error.message,
      });
      reply.status(500).send({
        error: 'Failed to update payment method',
        message: error.message,
      });
    }
  }

  /**
   * GET /api/subscriptions/invoices - Get billing history
   */
  async getInvoices(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    try {
      const userId = (request as any).user.sub;

      const invoices = await this.service.getInvoices(userId);

      reply.status(200).send(invoices);
    } catch (error: any) {
      logger.error('Failed to get invoices', {
        userId: (request as any).user?.sub,
        error: error.message,
      });
      reply.status(500).send({
        error: 'Failed to get invoices',
        message: error.message,
      });
    }
  }

  /**
   * POST /api/subscriptions/downgrade - Downgrade subscription with vehicle selection
   */
  async downgrade(
    request: FastifyRequest<{
      Body: {
        targetTier: 'free' | 'pro';
        vehicleIdsToKeep: string[];
      };
    }>,
    reply: FastifyReply
  ): Promise<void> {
    try {
      const userId = (request as any).user.sub;
      const { targetTier, vehicleIdsToKeep } = request.body;

      // Validate inputs
      if (!targetTier || !vehicleIdsToKeep) {
        reply.status(400).send({
          error: 'Missing required fields',
          message: 'targetTier and vehicleIdsToKeep are required',
        });
        return;
      }

      if (!['free', 'pro'].includes(targetTier)) {
        reply.status(400).send({
          error: 'Invalid tier',
          message: 'targetTier must be "free" or "pro"',
        });
        return;
      }

      if (!Array.isArray(vehicleIdsToKeep)) {
        reply.status(400).send({
          error: 'Invalid vehicle selection',
          message: 'vehicleIdsToKeep must be an array',
        });
        return;
      }

      // Downgrade subscription
      const updatedSubscription = await this.service.downgradeSubscription(
        userId,
        targetTier,
        vehicleIdsToKeep
      );

      reply.status(200).send(updatedSubscription);
    } catch (error: any) {
      logger.error('Failed to downgrade subscription', {
        userId: (request as any).user?.sub,
        error: error.message,
      });
      reply.status(500).send({
        error: 'Failed to downgrade subscription',
        message: error.message,
      });
    }
  }
}
