/**
 * Pricing Configuration Routes
 *
 * CRUD endpoints for pricing categories, items, rules, discounts, taxes, addons,
 * plus a public calculation endpoint for live price preview.
 *
 * All CRUD routes require super-admin role.
 * The calculate endpoint requires authentication.
 */

import { Router, Request, Response } from 'express';
import { PricingCategory } from '../models/PricingCategory';
import { PricingItem } from '../models/PricingItem';
import { PricingRule } from '../models/PricingRule';
import { PricingDiscount } from '../models/PricingDiscount';
import { PricingTax } from '../models/PricingTax';
import { PricingAddon } from '../models/PricingAddon';
import { calculatePricing, getCategoriesWithItems, getAddonsByCategory, computePackageLimits, PricingContext } from '../services/pricingEngine';
import { authenticate, requireRole } from '../middleware/auth';

const router = Router();

// All routes require authentication
router.use(authenticate);

// ============================================
// AUTH MIDDLEWARE (imported from auth module)
// ============================================

// These will be applied when the router is mounted in index.ts
// import { authenticate, requireRole } from '../middleware/auth';

// ============================================
// PRICING CATEGORIES
// ============================================

// List all categories (with items)
router.get('/categories', async (req: Request, res: Response) => {
  try {
    const categories = await getCategoriesWithItems();
    res.json({ data: categories });
  } catch (error: any) {
    console.error('Error fetching pricing categories:', error);
    res.status(500).json({ error: 'Failed to fetch pricing categories' });
  }
});

// Create category (super-admin only)
router.post('/categories', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    // A slug carries a unique index, and delete is a SOFT delete (isActive:false)
    // that leaves the document — and its slug — in place. Without this, recreating
    // a category whose slug was previously used (even one that was deleted) hit the
    // unique index and returned a spurious 409 for otherwise-valid input (Bug #37).
    // Only an ACTIVE category with the same slug is a genuine duplicate; a
    // soft-deleted one is revived with the new data instead.
    const existing = await PricingCategory.findOne({ slug: req.body.slug });
    if (existing) {
      if (existing.isActive) {
        return res.status(409).json({ error: 'Category slug already exists' });
      }
      existing.set({ ...req.body, isActive: true });
      await existing.save();
      return res.status(201).json({ data: existing });
    }

    const category = await PricingCategory.create(req.body);
    res.status(201).json({ data: category });
  } catch (error: any) {
    if (error.code === 11000) {
      return res.status(409).json({ error: 'Category slug already exists' });
    }
    console.error('Error creating pricing category:', error);
    res.status(500).json({ error: 'Failed to create pricing category' });
  }
});

// Update category (super-admin only)
router.put('/categories/:slug', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const category = await PricingCategory.findOneAndUpdate(
      { slug: req.params.slug },
      req.body,
      { new: true, runValidators: true },
    );
    if (!category) {
      return res.status(404).json({ error: 'Category not found' });
    }
    res.json({ data: category });
  } catch (error: any) {
    console.error('Error updating pricing category:', error);
    res.status(500).json({ error: 'Failed to update pricing category' });
  }
});

// Soft-delete category (super-admin only)
router.delete('/categories/:slug', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const category = await PricingCategory.findOneAndUpdate(
      { slug: req.params.slug },
      { isActive: false },
      { new: true },
    );
    if (!category) {
      return res.status(404).json({ error: 'Category not found' });
    }
    res.json({ data: category });
  } catch (error: any) {
    console.error('Error deleting pricing category:', error);
    res.status(500).json({ error: 'Failed to delete pricing category' });
  }
});

// ============================================
// PRICING ITEMS
// ============================================

// List items (optional ?categorySlug= filter)
router.get('/items', async (req: Request, res: Response) => {
  try {
    const filter: Record<string, unknown> = { isActive: true };
    if (req.query.categorySlug) {
      filter.categorySlug = req.query.categorySlug as string;
    }
    const items = await PricingItem.find(filter).sort({ categorySlug: 1, sortOrder: 1 });
    res.json({ data: items });
  } catch (error: any) {
    console.error('Error fetching pricing items:', error);
    res.status(500).json({ error: 'Failed to fetch pricing items' });
  }
});

// Get single item
router.get('/items/:slug', async (req: Request, res: Response) => {
  try {
    const item = await PricingItem.findOne({ slug: req.params.slug });
    if (!item) {
      return res.status(404).json({ error: 'Item not found' });
    }
    res.json({ data: item });
  } catch (error: any) {
    console.error('Error fetching pricing item:', error);
    res.status(500).json({ error: 'Failed to fetch pricing item' });
  }
});

// Create item (super-admin only)
router.post('/items', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const item = await PricingItem.create(req.body);
    res.status(201).json({ data: item });
  } catch (error: any) {
    if (error.code === 11000) {
      return res.status(409).json({ error: 'Item slug already exists' });
    }
    console.error('Error creating pricing item:', error);
    res.status(500).json({ error: 'Failed to create pricing item' });
  }
});

// Update item (super-admin only)
router.put('/items/:slug', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const item = await PricingItem.findOneAndUpdate(
      { slug: req.params.slug },
      req.body,
      { new: true, runValidators: true },
    );
    if (!item) {
      return res.status(404).json({ error: 'Item not found' });
    }
    res.json({ data: item });
  } catch (error: any) {
    console.error('Error updating pricing item:', error);
    res.status(500).json({ error: 'Failed to update pricing item' });
  }
});

// Soft-delete item (super-admin only)
router.delete('/items/:slug', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const item = await PricingItem.findOneAndUpdate(
      { slug: req.params.slug },
      { isActive: false },
      { new: true },
    );
    if (!item) {
      return res.status(404).json({ error: 'Item not found' });
    }
    res.json({ data: item });
  } catch (error: any) {
    console.error('Error deleting pricing item:', error);
    res.status(500).json({ error: 'Failed to delete pricing item' });
  }
});

// ============================================
// PRICING RULES
// ============================================

router.get('/rules', async (req: Request, res: Response) => {
  try {
    const rules = await PricingRule.find({ isActive: true }).sort({ priority: 1 });
    res.json({ data: rules });
  } catch (error: any) {
    console.error('Error fetching pricing rules:', error);
    res.status(500).json({ error: 'Failed to fetch pricing rules' });
  }
});

router.post('/rules', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const rule = await PricingRule.create(req.body);
    res.status(201).json({ data: rule });
  } catch (error: any) {
    if (error.code === 11000) {
      return res.status(409).json({ error: 'Rule slug already exists' });
    }
    console.error('Error creating pricing rule:', error);
    res.status(500).json({ error: 'Failed to create pricing rule' });
  }
});

router.put('/rules/:slug', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const rule = await PricingRule.findOneAndUpdate(
      { slug: req.params.slug },
      req.body,
      { new: true, runValidators: true },
    );
    if (!rule) {
      return res.status(404).json({ error: 'Rule not found' });
    }
    res.json({ data: rule });
  } catch (error: any) {
    console.error('Error updating pricing rule:', error);
    res.status(500).json({ error: 'Failed to update pricing rule' });
  }
});

router.delete('/rules/:slug', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const rule = await PricingRule.findOneAndUpdate(
      { slug: req.params.slug },
      { isActive: false },
      { new: true },
    );
    if (!rule) {
      return res.status(404).json({ error: 'Rule not found' });
    }
    res.json({ data: rule });
  } catch (error: any) {
    console.error('Error deleting pricing rule:', error);
    res.status(500).json({ error: 'Failed to delete pricing rule' });
  }
});

// ============================================
// PRICING DISCOUNTS
// ============================================

router.get('/discounts', async (req: Request, res: Response) => {
  try {
    const discounts = await PricingDiscount.find().sort({ code: 1 });
    res.json({ data: discounts });
  } catch (error: any) {
    console.error('Error fetching pricing discounts:', error);
    res.status(500).json({ error: 'Failed to fetch pricing discounts' });
  }
});

router.post('/discounts', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const discount = await PricingDiscount.create(req.body);
    res.status(201).json({ data: discount });
  } catch (error: any) {
    if (error.code === 11000) {
      return res.status(409).json({ error: 'Discount code already exists' });
    }
    console.error('Error creating pricing discount:', error);
    res.status(500).json({ error: 'Failed to create pricing discount' });
  }
});

router.put('/discounts/:code', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const discount = await PricingDiscount.findOneAndUpdate(
      { code: req.params.code.toUpperCase() },
      req.body,
      { new: true, runValidators: true },
    );
    if (!discount) {
      return res.status(404).json({ error: 'Discount not found' });
    }
    res.json({ data: discount });
  } catch (error: any) {
    console.error('Error updating pricing discount:', error);
    res.status(500).json({ error: 'Failed to update pricing discount' });
  }
});

router.delete('/discounts/:code', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const discount = await PricingDiscount.findOneAndUpdate(
      { code: req.params.code.toUpperCase() },
      { isActive: false },
      { new: true },
    );
    if (!discount) {
      return res.status(404).json({ error: 'Discount not found' });
    }
    res.json({ data: discount });
  } catch (error: any) {
    console.error('Error deleting pricing discount:', error);
    res.status(500).json({ error: 'Failed to delete pricing discount' });
  }
});

// ============================================
// PRICING TAXES
// ============================================

router.get('/taxes', async (req: Request, res: Response) => {
  try {
    const taxes = await PricingTax.find().sort({ country: 1, rate: 1 });
    res.json({ data: taxes });
  } catch (error: any) {
    console.error('Error fetching pricing taxes:', error);
    res.status(500).json({ error: 'Failed to fetch pricing taxes' });
  }
});

router.post('/taxes', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const tax = await PricingTax.create(req.body);
    res.status(201).json({ data: tax });
  } catch (error: any) {
    if (error.code === 11000) {
      return res.status(409).json({ error: 'Tax code already exists' });
    }
    console.error('Error creating pricing tax:', error);
    res.status(500).json({ error: 'Failed to create pricing tax' });
  }
});

router.put('/taxes/:code', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const tax = await PricingTax.findOneAndUpdate(
      { code: req.params.code.toUpperCase() },
      req.body,
      { new: true, runValidators: true },
    );
    if (!tax) {
      return res.status(404).json({ error: 'Tax not found' });
    }
    res.json({ data: tax });
  } catch (error: any) {
    console.error('Error updating pricing tax:', error);
    res.status(500).json({ error: 'Failed to update pricing tax' });
  }
});

router.delete('/taxes/:code', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const tax = await PricingTax.findOneAndUpdate(
      { code: req.params.code.toUpperCase() },
      { isActive: false },
      { new: true },
    );
    if (!tax) {
      return res.status(404).json({ error: 'Tax not found' });
    }
    res.json({ data: tax });
  } catch (error: any) {
    console.error('Error deleting pricing tax:', error);
    res.status(500).json({ error: 'Failed to delete pricing tax' });
  }
});

// ============================================
// PRICING ADDONS
// ============================================

router.get('/addons', async (req: Request, res: Response) => {
  try {
    const addons = await PricingAddon.find({ isActive: true }).sort({ categorySlug: 1, sortOrder: 1 });
    res.json({ data: addons });
  } catch (error: any) {
    console.error('Error fetching pricing addons:', error);
    res.status(500).json({ error: 'Failed to fetch pricing addons' });
  }
});

router.get('/addons/grouped', async (req: Request, res: Response) => {
  try {
    const grouped = await getAddonsByCategory();
    res.json({ data: grouped });
  } catch (error: any) {
    console.error('Error fetching grouped addons:', error);
    res.status(500).json({ error: 'Failed to fetch grouped addons' });
  }
});

router.post('/addons', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const addon = await PricingAddon.create(req.body);
    res.status(201).json({ data: addon });
  } catch (error: any) {
    if (error.code === 11000) {
      return res.status(409).json({ error: 'Addon slug already exists' });
    }
    console.error('Error creating pricing addon:', error);
    res.status(500).json({ error: 'Failed to create pricing addon' });
  }
});

router.put('/addons/:slug', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const addon = await PricingAddon.findOneAndUpdate(
      { slug: req.params.slug },
      req.body,
      { new: true, runValidators: true },
    );
    if (!addon) {
      return res.status(404).json({ error: 'Addon not found' });
    }
    res.json({ data: addon });
  } catch (error: any) {
    console.error('Error updating pricing addon:', error);
    res.status(500).json({ error: 'Failed to update pricing addon' });
  }
});

router.delete('/addons/:slug', requireRole('super-admin'), async (req: Request, res: Response) => {
  try {
    const addon = await PricingAddon.findOneAndUpdate(
      { slug: req.params.slug },
      { isActive: false },
      { new: true },
    );
    if (!addon) {
      return res.status(404).json({ error: 'Addon not found' });
    }
    res.json({ data: addon });
  } catch (error: any) {
    console.error('Error deleting pricing addon:', error);
    res.status(500).json({ error: 'Failed to delete pricing addon' });
  }
});

// ============================================
// CALCULATE PRICING (PUBLIC - ANY AUTHENTICATED USER)
// ============================================

router.post('/calculate', async (req: Request, res: Response) => {
  try {
    const context: PricingContext = {
      billingCycle: req.body.billingCycle || 'monthly',
      currency: req.body.currency || 'USD',
      selectedItems: req.body.selectedItems || [],
      selectedAddons: req.body.selectedAddons || [],
      discountCodes: req.body.discountCodes || [],
      quantityOverrides: req.body.quantityOverrides,
      countryCode: req.body.countryCode,
    };

    // Validate billing cycle
    const validCycles = ['monthly', 'quarterly', 'half_yearly', 'yearly', 'lifetime'];
    if (!validCycles.includes(context.billingCycle)) {
      return res.status(400).json({ error: `Invalid billing cycle. Must be one of: ${validCycles.join(', ')}` });
    }

    // Validate that arrays are provided
    if (!Array.isArray(context.selectedItems)) {
      return res.status(400).json({ error: 'selectedItems must be an array' });
    }
    if (!Array.isArray(context.selectedAddons)) {
      return res.status(400).json({ error: 'selectedAddons must be an array' });
    }
    if (!Array.isArray(context.discountCodes)) {
      return res.status(400).json({ error: 'discountCodes must be an array' });
    }

    const result = await calculatePricing(context);
    res.json({ data: result });
  } catch (error: any) {
    console.error('Error calculating pricing:', error);
    res.status(500).json({ error: 'Failed to calculate pricing' });
  }
});

// ============================================
// COMPUTE LIMITS (for package builder)
// ============================================

router.post('/compute-limits', async (req: Request, res: Response) => {
  try {
    const { selectedItemSlugs, selectedAddonSlugs, quantityOverrides } = req.body;

    if (!Array.isArray(selectedItemSlugs)) {
      return res.status(400).json({ error: 'selectedItemSlugs must be an array' });
    }
    if (!Array.isArray(selectedAddonSlugs)) {
      return res.status(400).json({ error: 'selectedAddonSlugs must be an array' });
    }

    const limits = await computePackageLimits(selectedItemSlugs, selectedAddonSlugs, quantityOverrides);
    res.json({ data: limits });
  } catch (error: any) {
    console.error('Error computing limits:', error);
    res.status(500).json({ error: 'Failed to compute limits' });
  }
});

export default router;