/**
 * Onboarding Routes
 *
 * Public and authenticated endpoints for in-plugin onboarding:
 * tier selection, mock payment checkout, and subscription status.
 */

import { Router, Request, Response } from 'express';
import { PrismaClient } from '@prisma/client';
import { z } from 'zod';
import { validate } from '../middleware/validator';
import { authenticateJWT, authenticateApiKey } from '../middleware/auth';
import { requireNonProduction } from '../middleware/requireNonProduction';
import { successResponse, errorResponse } from '../utils/errorHandler';
import { tierService } from '../services/tierService';
import { createLicense, activateLicense } from '../services/multilingualLicenseService';
import { createApiKey } from '../auth/apiKeyService';
import { allocateCredits } from '../services/creditService';
import { logger } from '../utils/logger';
import { publicRateLimiter } from '../middleware/rateLimiter';

const router = Router();
const prisma = new PrismaClient();

// Validation schemas
const checkoutSchema = z.object({
  tier_slug: z.string().min(1).max(50),
  billing_cycle: z.enum(['monthly', 'annual']),
  plugin: z.enum(['translate', 'multilingual', 'international']),
  site_url: z.string().url('site_url must be a valid URL'),
});

/**
 * GET /plans
 * Get available tiers for a plugin (public, no auth required)
 */
router.get('/plans', publicRateLimiter, async (req: Request, res: Response) => {
  try {
    const plugin = req.query.plugin as string;

    if (!plugin || !['translate', 'multilingual', 'international'].includes(plugin)) {
      return res.status(400).json(
        errorResponse('INVALID_PLUGIN', 'plugin query parameter must be "translate", "multilingual", or "international"')
      );
    }

    const tiers = await tierService.getActiveTiersByPlugin(plugin);

    const plans = tiers.map((tier) => ({
      slug: tier.slug,
      name: tier.name,
      description: tier.description,
      monthly_price: parseFloat(tier.monthly_price.toString()),
      annual_price: parseFloat(tier.annual_price.toString()),
      credit_allocation: tier.credit_allocation,
      features: tier.features as string[],
      plugin_limits: tier.plugin_limits as Record<string, any>,
      rate_limit: tier.rate_limit,
    }));

    return res.json(successResponse({ plans }));
  } catch (error) {
    logger.error('Failed to fetch onboarding plans', { error });
    return res.status(500).json(
      errorResponse('INTERNAL_ERROR', 'Failed to fetch plans')
    );
  }
});

/**
 * GET /subscription-status
 * Check if user has an active subscription for a given plugin (JWT-authenticated)
 */
router.get('/subscription-status', authenticateJWT, async (req: Request, res: Response) => {
  try {
    if (!req.user) {
      return res.status(401).json(errorResponse('UNAUTHORIZED', 'Authentication required'));
    }

    const plugin = req.query.plugin as string;
    if (!plugin || !['translate', 'multilingual', 'international'].includes(plugin)) {
      return res.status(400).json(
        errorResponse('INVALID_PLUGIN', 'plugin query parameter must be "translate", "multilingual", or "international"')
      );
    }

    const subscription = await prisma.subscription.findUnique({
      where: {
        user_id_plugin: {
          user_id: req.user.userId,
          plugin,
        },
      },
    });

    if (!subscription || subscription.status !== 'active') {
      return res.json(successResponse({
        has_active_subscription: false,
        subscription: null,
      }));
    }

    return res.json(successResponse({
      has_active_subscription: true,
      subscription: {
        plugin: subscription.plugin,
        tier: subscription.plan_tier,
        status: subscription.status,
        current_period_end: subscription.current_period_end.toISOString(),
      },
    }));
  } catch (error) {
    logger.error('Failed to check subscription status', { error });
    return res.status(500).json(
      errorResponse('INTERNAL_ERROR', 'Failed to check subscription status')
    );
  }
});

/**
 * POST /checkout
 * Mock payment checkout — creates subscription, payment, credits, license, and API key
 * in a single transaction (JWT-authenticated).
 * Non-production only; use /v1/subscriptions/checkout for real payment flow.
 */
router.post('/checkout', requireNonProduction, authenticateJWT, validate(checkoutSchema), async (req: Request, res: Response) => {
  try {
    if (!req.user) {
      return res.status(401).json(errorResponse('UNAUTHORIZED', 'Authentication required'));
    }

    const { tier_slug, billing_cycle, plugin, site_url } = req.body;
    const userId = req.user.userId;

    // 1. Validate tier exists and is active for the plugin
    const tier = await tierService.getTierBySlug(tier_slug, plugin);
    if (!tier || !tier.is_active) {
      return res.status(400).json(
        errorResponse('INVALID_TIER', `No active tier "${tier_slug}" found for plugin "${plugin}"`)
      );
    }

    const price = billing_cycle === 'annual'
      ? parseFloat(tier.annual_price.toString())
      : parseFloat(tier.monthly_price.toString());

    const periodEnd = new Date();
    if (billing_cycle === 'annual') {
      periodEnd.setFullYear(periodEnd.getFullYear() + 1);
    } else {
      periodEnd.setMonth(periodEnd.getMonth() + 1);
    }

    // 2. Run everything in a transaction
    const result = await prisma.$transaction(async (tx) => {
      // 2a. Upsert subscription
      const subscription = await tx.subscription.upsert({
        where: {
          user_id_plugin: {
            user_id: userId,
            plugin,
          },
        },
        update: {
          plan_tier: tier_slug,
          billing_cycle,
          status: 'active',
          current_period_start: new Date(),
          current_period_end: periodEnd,
        },
        create: {
          user_id: userId,
          plugin,
          plan_tier: tier_slug,
          billing_cycle,
          status: 'active',
          current_period_start: new Date(),
          current_period_end: periodEnd,
        },
      });

      // 2b. Create payment record
      const payment = await tx.payment.create({
        data: {
          user_id: userId,
          amount: price,
          currency: 'USD',
          status: 'completed',
          type: 'subscription_payment',
          subscription_id: subscription.id,
        },
      });

      return { subscription, payment };
    });

    // 3. Allocate credits (outside transaction since creditService uses its own)
    await allocateCredits(
      userId,
      tier.credit_allocation,
      `${plugin} subscription activation — ${tier.name} (${billing_cycle})`,
      result.payment.id
    );

    // 4. Create license
    // Map tier slug to license plan tier
    const licensePlanTier = tier_slug; // starter/professional/enterprise
    const sitesAllowed = (() => {
      switch (tier_slug) {
        case 'starter': return 3;
        case 'professional': return 10;
        case 'enterprise': return -1; // unlimited
        default: return 3;
      }
    })();

    const licenseResult = await createLicense({
      plan_tier: licensePlanTier,
      sites_allowed: sitesAllowed,
      expires_at: result.subscription.current_period_end,
      plugin,
    });

    // 5. Activate license on site_url
    const licenseInfo = await activateLicense({
      license_key: licenseResult.license_key,
      site_url,
      plugin,
    });

    // 6. Create API key (both plugins need it for upgrade/account endpoints)
    const apiKey = await createApiKey(userId, `onboarding-${plugin}-${site_url}`);
    const apiKeyResult = { key: apiKey.key, prefix: apiKey.prefix };

    logger.info('Onboarding checkout completed', {
      userId,
      plugin,
      tier: tier_slug,
      billingCycle: billing_cycle,
      licenseKeyLast4: licenseResult.license.key_last4,
    });

    return res.status(201).json(successResponse({
      license_key: licenseResult.license_key,
      api_key: apiKeyResult.key,
      subscription: {
        plugin: result.subscription.plugin,
        tier: result.subscription.plan_tier,
        status: result.subscription.status,
        current_period_end: result.subscription.current_period_end.toISOString(),
      },
      credits_allocated: tier.credit_allocation,
      license: {
        tier: licenseInfo.tier,
        status: licenseInfo.status,
        sites_allowed: licenseInfo.sites_allowed,
        languages_allowed: licenseInfo.languages_allowed,
        expires_at: licenseInfo.expires_at,
      },
    }));
  } catch (error) {
    logger.error('Onboarding checkout failed', {
      userId: req.user?.userId,
      error: error instanceof Error ? error.message : 'Unknown error',
      stack: error instanceof Error ? error.stack : undefined,
    });

    return res.status(500).json(
      errorResponse('CHECKOUT_FAILED', 'Failed to complete checkout')
    );
  }
});

/**
 * POST /upgrade
 * Upgrade subscription tier — same logic as checkout but accepts API key auth
 * (used from plugin licensing page where JWT is not available).
 * Non-production only; use /v1/subscriptions/checkout for real payment flow.
 */
router.post('/upgrade', requireNonProduction, authenticateApiKey, validate(checkoutSchema), async (req: Request, res: Response) => {
  try {
    if (!req.user) {
      return res.status(401).json(errorResponse('UNAUTHORIZED', 'Authentication required'));
    }

    const { tier_slug, billing_cycle, plugin, site_url } = req.body;
    const userId = req.user.userId;

    // 1. Validate tier exists and is active for the plugin
    const tier = await tierService.getTierBySlug(tier_slug, plugin);
    if (!tier || !tier.is_active) {
      return res.status(400).json(
        errorResponse('INVALID_TIER', `No active tier "${tier_slug}" found for plugin "${plugin}"`)
      );
    }

    const price = billing_cycle === 'annual'
      ? parseFloat(tier.annual_price.toString())
      : parseFloat(tier.monthly_price.toString());

    const periodEnd = new Date();
    if (billing_cycle === 'annual') {
      periodEnd.setFullYear(periodEnd.getFullYear() + 1);
    } else {
      periodEnd.setMonth(periodEnd.getMonth() + 1);
    }

    // 2. Run everything in a transaction
    const result = await prisma.$transaction(async (tx) => {
      // 2a. Upsert subscription
      const subscription = await tx.subscription.upsert({
        where: {
          user_id_plugin: {
            user_id: userId,
            plugin,
          },
        },
        update: {
          plan_tier: tier_slug,
          billing_cycle,
          status: 'active',
          current_period_start: new Date(),
          current_period_end: periodEnd,
        },
        create: {
          user_id: userId,
          plugin,
          plan_tier: tier_slug,
          billing_cycle,
          status: 'active',
          current_period_start: new Date(),
          current_period_end: periodEnd,
        },
      });

      // 2b. Create payment record
      const payment = await tx.payment.create({
        data: {
          user_id: userId,
          amount: price,
          currency: 'USD',
          status: 'completed',
          type: 'subscription_payment',
          subscription_id: subscription.id,
        },
      });

      return { subscription, payment };
    });

    // 3. Allocate credits
    await allocateCredits(
      userId,
      tier.credit_allocation,
      `${plugin} subscription upgrade — ${tier.name} (${billing_cycle})`,
      result.payment.id
    );

    // 4. Create/update license
    const licensePlanTier = tier_slug;
    const sitesAllowed = (() => {
      switch (tier_slug) {
        case 'starter': return 3;
        case 'professional': return 10;
        case 'enterprise': return -1;
        default: return 3;
      }
    })();

    const licenseResult = await createLicense({
      plan_tier: licensePlanTier,
      sites_allowed: sitesAllowed,
      expires_at: result.subscription.current_period_end,
      plugin,
    });

    const licenseInfo = await activateLicense({
      license_key: licenseResult.license_key,
      site_url,
      plugin,
    });

    logger.info('Onboarding upgrade completed', {
      userId,
      plugin,
      tier: tier_slug,
      billingCycle: billing_cycle,
    });

    return res.status(201).json(successResponse({
      license_key: licenseResult.license_key,
      subscription: {
        plugin: result.subscription.plugin,
        tier: result.subscription.plan_tier,
        status: result.subscription.status,
        current_period_end: result.subscription.current_period_end.toISOString(),
      },
      credits_allocated: tier.credit_allocation,
      license: {
        tier: licenseInfo.tier,
        status: licenseInfo.status,
        sites_allowed: licenseInfo.sites_allowed,
        languages_allowed: licenseInfo.languages_allowed,
        expires_at: licenseInfo.expires_at,
      },
    }));
  } catch (error) {
    logger.error('Onboarding upgrade failed', {
      userId: req.user?.userId,
      error: error instanceof Error ? error.message : 'Unknown error',
      stack: error instanceof Error ? error.stack : undefined,
    });

    return res.status(500).json(
      errorResponse('UPGRADE_FAILED', 'Failed to complete upgrade')
    );
  }
});

export default router;
