import { FastifyInstance } from 'fastify';
import { BillingService } from '@shieldai/shared-billing/src/services/billing.service';
import { SubscriptionService, customerService, webhookService } from '@shieldai/shared-billing/src/services/billing.services';
import { SubscriptionTier, isValidReturnUrl } from '@shieldai/shared-billing/src/config/billing.config';
import { AuthRequest } from './auth.middleware';

const billingService = BillingService.getInstance();
const subscriptionService = new SubscriptionService();

export async function subscriptionRoutes(fastify: FastifyInstance) {
  // Get current user's subscription
  fastify.get(
    '/subscription',
    {
      preHandler: async (request, reply) => {
        await fastify.requireAuth(request as AuthRequest);
      },
    },
    async (request, reply) => {
      const authReq = request as AuthRequest;
      
      try {
        const subscription = await billingService.getUserSubscription(authReq.user!.id);
        
        if (!subscription) {
          return reply.status(404).send({
            error: 'No active subscription found',
            message: 'Please create a subscription to access premium features',
          });
        }

        return {
          subscription: {
            id: subscription.id,
            status: subscription.status,
            currentPeriodStart: new Date(subscription.current_period_start * 1000).toISOString(),
            currentPeriodEnd: new Date(subscription.current_period_end * 1000).toISOString(),
            cancelAtPeriodEnd: subscription.cancel_at_period_end,
            created: new Date(subscription.created * 1000).toISOString(),
          },
          customer: {
            id: subscription.customer as string,
          },
        };
      } catch (error) {
        reply.status(500).send({
          error: 'Failed to fetch subscription',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );

  // Create a new subscription (for mobile app in-app purchases)
  fastify.post(
    '/subscription/create',
    {
      preHandler: async (request, reply) => {
        await fastify.requireAuth(request as AuthRequest);
      },
    },
    async (request, reply) => {
      const authReq = request as AuthRequest;
      const { tier, customerId } = request.body as { tier: SubscriptionTier; customerId: string };

      if (!authReq.user?.id) {
        return reply.status(401).send({ error: 'Authentication required' });
      }

      if (!tier || !customerId) {
        return reply.status(400).send({
          error: 'Missing required fields',
          required: ['tier', 'customerId'],
        });
      }

      try {
        const result = await billingService.createSubscription(
          authReq.user.id,
          tier,
          customerId
        );

        return {
          subscription: {
            id: result.subscription.id,
            status: result.subscription.status,
            currentPeriodStart: new Date(result.subscription.current_period_start * 1000).toISOString(),
            currentPeriodEnd: new Date(result.subscription.current_period_end * 1000).toISOString(),
          },
          customer: {
            id: result.customer.id,
            email: result.customer.email,
          },
        };
      } catch (error) {
        reply.status(500).send({
          error: 'Failed to create subscription',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );

  // Update subscription tier
  fastify.put(
    '/subscription/:subscriptionId/tier',
    {
      preHandler: async (request, reply) => {
        await fastify.requireAuth(request as AuthRequest);
      },
    },
    async (request, reply) => {
      const authReq = request as AuthRequest;
      const { subscriptionId } = request.params as { subscriptionId: string };
      const { tier } = request.body as { tier: SubscriptionTier };

      if (!authReq.user?.id) {
        return reply.status(401).send({ error: 'Authentication required' });
      }

      if (!tier) {
        return reply.status(400).send({
          error: 'Missing required field',
          required: ['tier'],
        });
      }

      try {
        const updated = await billingService.updateSubscription(
          subscriptionId,
          authReq.user.id,
          tier
        );

        return {
          subscription: {
            id: updated.id,
            status: updated.status,
            currentPeriodStart: new Date(updated.current_period_start * 1000).toISOString(),
            currentPeriodEnd: new Date(updated.current_period_end * 1000).toISOString(),
          },
          message: 'Subscription updated successfully',
        };
      } catch (error) {
        reply.status(500).send({
          error: 'Failed to update subscription',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );

  // Cancel subscription
  fastify.delete(
    '/subscription/:subscriptionId',
    {
      preHandler: async (request, reply) => {
        await fastify.requireAuth(request as AuthRequest);
      },
    },
    async (request, reply) => {
      const authReq = request as AuthRequest;
      const { subscriptionId } = request.params as { subscriptionId: string };
      const { cancelAtPeriodEnd } = request.body as { cancelAtPeriodEnd?: boolean };

      if (!authReq.user?.id) {
        return reply.status(401).send({ error: 'Authentication required' });
      }

      try {
        const cancelled = await billingService.cancelSubscription(
          subscriptionId,
          authReq.user.id,
          cancelAtPeriodEnd ?? true
        );

        return {
          subscription: {
            id: cancelled.id,
            status: cancelled.status,
            cancelAtPeriodEnd: cancelled.cancel_at_period_end,
            canceledAt: cancelled.canceled_at ? new Date(cancelled.canceled_at * 1000).toISOString() : null,
          },
          message: cancelAtPeriodEnd
            ? 'Subscription will cancel at the end of the billing period'
            : 'Subscription cancelled immediately',
        };
      } catch (error) {
        reply.status(500).send({
          error: 'Failed to cancel subscription',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );

  // Create customer portal session
  fastify.post(
    '/customer/portal',
    {
      preHandler: async (request, reply) => {
        await fastify.requireAuth(request as AuthRequest);
      },
    },
    async (request, reply) => {
      const authReq = request as AuthRequest;
      const { customerId, returnUrl } = request.body as { customerId: string; returnUrl: string };

      if (!authReq.user?.id) {
        return reply.status(401).send({ error: 'Authentication required' });
      }

      if (!customerId || !returnUrl) {
        return reply.status(400).send({
          error: 'Missing required fields',
          required: ['customerId', 'returnUrl'],
        });
      }

      if (!isValidReturnUrl(returnUrl)) {
        return reply.status(400).send({
          error: 'Invalid return URL',
          message: 'returnUrl must be from an allowed origin',
        });
      }

      try {
        const portalSession = await billingService.createCustomerPortalSession(
          customerId,
          returnUrl
        );

        return {
          url: portalSession.url,
          expiresAt: new Date(portalSession.expires_at * 1000).toISOString(),
        };
      } catch (error) {
        reply.status(500).send({
          error: 'Failed to create portal session',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );

  // Create customer
  fastify.post(
    '/customer',
    {
      preHandler: async (request, reply) => {
        await fastify.requireAuth(request as AuthRequest);
      },
    },
    async (request, reply) => {
      const authReq = request as AuthRequest;
      const { email, name } = request.body as { email: string; name?: string };

      if (!authReq.user?.id) {
        return reply.status(401).send({ error: 'Authentication required' });
      }

      if (!email) {
        return reply.status(400).send({
          error: 'Email is required',
        });
      }

      try {
        const customer = await billingService.createCustomer(email, authReq.user.id);

        return {
          customer: {
            id: customer.id,
            email: customer.email,
            name: customer.name,
            metadata: customer.metadata,
          },
        };
      } catch (error) {
        reply.status(500).send({
          error: 'Failed to create customer',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );

  // Get user tier
  fastify.get(
    '/user/tier',
    {
      preHandler: async (request, reply) => {
        await fastify.requireAuth(request as AuthRequest);
      },
    },
    async (request, reply) => {
      const authReq = request as AuthRequest;

      if (!authReq.user?.id) {
        return reply.status(401).send({ error: 'Authentication required' });
      }

      try {
        const tier = await billingService.getUserTier(authReq.user.id);

        if (!tier) {
          return {
            tier: 'free' as SubscriptionTier,
            limits: await billingService.getTierLimits('free'),
          };
        }

        const limits = await billingService.getTierLimits(tier);

        return {
          tier,
          limits,
        };
      } catch (error) {
        reply.status(500).send({
          error: 'Failed to fetch user tier',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );

  // Get invoice history
  fastify.get(
    '/invoices',
    {
      preHandler: async (request, reply) => {
        await fastify.requireAuth(request as AuthRequest);
      },
    },
    async (request, reply) => {
      const authReq = request as AuthRequest;
      const { customerId } = request.query as { customerId?: string };

      if (!authReq.user?.id) {
        return reply.status(401).send({ error: 'Authentication required' });
      }

      if (!customerId) {
        return reply.status(400).send({
          error: 'customerId is required',
        });
      }

      // Verify the customer belongs to the authenticated user (IDOR prevention)
      try {
        await billingService.verifyCustomerOwnership(customerId, authReq.user.id);
      } catch {
        return reply.status(403).send({
          error: 'Forbidden',
          message: 'You do not have access to this customer',
        });
      }

      try {
        const invoices = await billingService.getInvoiceHistory(customerId);

        return {
          invoices: invoices.data.map((invoice) => ({
            id: invoice.id,
            amountDue: invoice.amount_due,
            amountPaid: invoice.amount_paid,
            status: invoice.status,
            created: new Date(invoice.created * 1000).toISOString(),
            hostedInvoiceUrl: invoice.hosted_invoice_url,
          })),
          hasMore: invoices.has_more,
        };
      } catch (error) {
        reply.status(500).send({
          error: 'Failed to fetch invoice history',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );

  // Webhook handler (public endpoint)
  fastify.post(
    '/webhooks/stripe',
    {
      // Skip authentication for webhooks
      preHandler: async (request, reply) => {
        // Don't require auth for webhooks
      },
    },
    async (request, reply) => {
      const sig = request.headers['stripe-signature'] as string;

      if (!sig) {
        return reply.status(400).send({
          error: 'Missing Stripe signature',
        });
      }

      try {
        const event = await billingService.handleWebhook(sig, request.rawBody as Buffer);

        if (!event) {
          return reply.status(200).send({
            received: true,
            message: 'Event already processed',
          });
        }

        // Handle different event types using webhook service
        await webhookService.handleWebhook(event);

        return { received: true };
      } catch (error) {
        console.error('Webhook error:', error);
        return reply.status(400).send({
          error: 'Webhook handler failed',
          message: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }
  );
}
