import { Router, Request, Response, NextFunction } from 'express';
import { authenticate } from '../../middleware/auth.middleware';
import { requireRole } from '../../middleware/rbac.middleware';
import { PAYMENTS_ROLES } from '../../utils/roles';
import { validate } from '../../middleware/validate';
import { paymentSettingsService } from './payment-settings.service';
import { subscriptionsService } from './subscriptions.service';
import { plansService } from './plans.service';
import { productsService } from './products.service';
import { donationsService } from './donations.service';
import {
  updatePaymentSettingsSchema,
  createPlanSchema,
  updatePlanSchema,
  listPlansSchema,
  createProductSchema,
  updateProductSchema,
  subscriptionFiltersSchema,
  orderFiltersSchema,
  refundDonationSchema,
} from './payments.schemas';

const router = Router();

// All admin routes require PAYMENTS_ROLES
router.use(authenticate, requireRole(...PAYMENTS_ROLES));

// =================== Settings ===================

// GET /api/payments/admin/settings
router.get('/settings', async (_req: Request, res: Response, next: NextFunction) => {
  try {
    const settings = await paymentSettingsService.get();
    // Mask secret key for display
    const masked = {
      ...settings,
      stripeSecretKey: settings.stripeSecretKey ? '••••' + settings.stripeSecretKey.slice(-4) : '',
      stripeWebhookSecret: settings.stripeWebhookSecret ? '••••' + settings.stripeWebhookSecret.slice(-4) : '',
    };
    res.setHeader('Cache-Control', 'no-store');
    res.json(masked);
  } catch (err) {
    next(err);
  }
});

// PUT /api/payments/admin/settings
router.put(
  '/settings',
  validate(updatePaymentSettingsSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const settings = await paymentSettingsService.update(req.body);
      // Mask secrets in response (same as GET) to prevent leaking decrypted keys
      const masked = {
        ...settings,
        stripeSecretKey: settings.stripeSecretKey ? '••••' + settings.stripeSecretKey.slice(-4) : '',
        stripeWebhookSecret: settings.stripeWebhookSecret ? '••••' + settings.stripeWebhookSecret.slice(-4) : '',
      };
      res.setHeader('Cache-Control', 'no-store');
      res.json(masked);
    } catch (err) {
      next(err);
    }
  }
);

// POST /api/payments/admin/settings/test-connection
router.post('/settings/test-connection', async (_req: Request, res: Response, next: NextFunction) => {
  try {
    const { getStripe } = await import('../../services/stripe.client');
    const stripe = await getStripe();
    // Simple test: list 1 product
    await stripe.products.list({ limit: 1 });
    res.json({ success: true, message: 'Stripe connection verified' });
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : 'Connection failed';
    res.json({ success: false, message });
  }
});

// =================== Dashboard ===================

// GET /api/payments/admin/dashboard
router.get('/dashboard', async (_req: Request, res: Response, next: NextFunction) => {
  try {
    const [subStats, donationStats] = await Promise.all([
      subscriptionsService.getDashboardStats(),
      donationsService.getDonationStats(),
    ]);
    res.json({
      ...subStats,
      donations: donationStats,
    });
  } catch (err) {
    next(err);
  }
});

// =================== Plans ===================

// GET /api/payments/admin/plans
router.get(
  '/plans',
  validate(listPlansSchema, 'query'),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const result = await plansService.findAll(req.query as Record<string, unknown> as Parameters<typeof plansService.findAll>[0]);
      res.json(result);
    } catch (err) {
      next(err);
    }
  }
);

// GET /api/payments/admin/plans/:id
router.get('/plans/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = parseInt(req.params.id as string, 10);
    const plan = await plansService.findById(id);
    res.json(plan);
  } catch (err) {
    next(err);
  }
});

// POST /api/payments/admin/plans
router.post(
  '/plans',
  validate(createPlanSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const plan = await plansService.create(req.body);
      res.status(201).json(plan);
    } catch (err) {
      next(err);
    }
  }
);

// PUT /api/payments/admin/plans/:id
router.put(
  '/plans/:id',
  validate(updatePlanSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const id = parseInt(req.params.id as string, 10);
      const plan = await plansService.update(id, req.body);
      res.json(plan);
    } catch (err) {
      next(err);
    }
  }
);

// DELETE /api/payments/admin/plans/:id
router.delete('/plans/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = parseInt(req.params.id as string, 10);
    await plansService.delete(id);
    res.json({ success: true });
  } catch (err) {
    next(err);
  }
});

// POST /api/payments/admin/plans/:id/sync-stripe
router.post('/plans/:id/sync-stripe', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = parseInt(req.params.id as string, 10);
    const plan = await subscriptionsService.syncPlanToStripe(id);
    res.json(plan);
  } catch (err) {
    next(err);
  }
});

// =================== Subscriptions ===================

// GET /api/payments/admin/subscriptions/export
router.get('/subscriptions/export', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const search = req.query.search as string | undefined;
    const status = req.query.status as import('@prisma/client').SubscriptionStatus | undefined;
    const planId = req.query.planId ? parseInt(req.query.planId as string, 10) : undefined;
    const csv = await subscriptionsService.exportToCsv({ search, status, planId });
    res.setHeader('Content-Type', 'text/csv');
    res.setHeader('Content-Disposition', 'attachment; filename=subscriptions-export.csv');
    res.send(csv);
  } catch (err) {
    next(err);
  }
});

// GET /api/payments/admin/subscriptions
router.get(
  '/subscriptions',
  validate(subscriptionFiltersSchema, 'query'),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const result = await subscriptionsService.listSubscriptions(req.query as Record<string, unknown> as Parameters<typeof subscriptionsService.listSubscriptions>[0]);
      res.json(result);
    } catch (err) {
      next(err);
    }
  }
);

// POST /api/payments/admin/subscriptions/:id/cancel
router.post('/subscriptions/:id/cancel', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const id = parseInt(req.params.id as string, 10);
    const immediate = req.body?.immediate === true;
    const sub = await subscriptionsService.cancelSubscription(id, immediate);
    res.json(sub);
  } catch (err) {
    next(err);
  }
});

// =================== Products ===================

// GET /api/payments/admin/products
router.get('/products', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const page = parseInt(req.query.page as string, 10) || 1;
    const limit = parseInt(req.query.limit as string, 10) || 20;
    const type = req.query.type as string | undefined;
    const search = req.query.search as string | undefined;
    const result = await productsService.listAll({ page, limit, type, search });
    res.json(result);
  } catch (err) {
    next(err);
  }
});

// POST /api/payments/admin/products
router.post(
  '/products',
  validate(createProductSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const product = await productsService.create({
        ...req.body,
        createdByUserId: req.user!.id,
      });
      res.status(201).json(product);
    } catch (err) {
      next(err);
    }
  }
);

// PUT /api/payments/admin/products/:id
router.put(
  '/products/:id',
  validate(updateProductSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const product = await productsService.update(req.params.id as string, req.body);
      res.json(product);
    } catch (err) {
      next(err);
    }
  }
);

// DELETE /api/payments/admin/products/:id
router.delete('/products/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    await productsService.delete(req.params.id as string);
    res.json({ success: true });
  } catch (err) {
    next(err);
  }
});

// POST /api/payments/admin/products/:id/sync-stripe
router.post('/products/:id/sync-stripe', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const product = await productsService.syncProductToStripe(req.params.id as string);
    res.json(product);
  } catch (err) {
    next(err);
  }
});

// =================== Orders ===================

// GET /api/payments/admin/orders
router.get(
  '/orders',
  validate(orderFiltersSchema, 'query'),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const result = await productsService.listOrders(req.query as Record<string, unknown> as Parameters<typeof productsService.listOrders>[0]);
      res.json(result);
    } catch (err) {
      next(err);
    }
  }
);

// POST /api/payments/admin/orders/:id/refund
router.post('/orders/:id/refund', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const order = await productsService.refundOrder(req.params.id as string);
    res.json(order);
  } catch (err) {
    next(err);
  }
});

// =================== Donations ===================

// GET /api/payments/admin/donations/export
router.get('/donations/export', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const search = req.query.search as string | undefined;
    const status = req.query.status as string | undefined;
    const donationPageId = req.query.donationPageId as string | undefined;
    const csv = await donationsService.exportToCsv({ search, status, donationPageId });
    res.setHeader('Content-Type', 'text/csv');
    res.setHeader('Content-Disposition', 'attachment; filename=donations-export.csv');
    res.send(csv);
  } catch (err) {
    next(err);
  }
});

// GET /api/payments/admin/donations
router.get('/donations', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const page = parseInt(req.query.page as string, 10) || 1;
    const limit = parseInt(req.query.limit as string, 10) || 20;
    const search = req.query.search as string | undefined;
    const donationPageId = req.query.donationPageId as string | undefined;
    const result = await donationsService.listDonations({ page, limit, search, donationPageId });
    res.json(result);
  } catch (err) {
    next(err);
  }
});

// POST /api/payments/admin/donations/:id/refund
router.post(
  '/donations/:id/refund',
  validate(refundDonationSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const order = await donationsService.refundDonation(
        req.params.id as string,
        req.body.reason,
      );
      res.json(order);
    } catch (err) {
      next(err);
    }
  }
);

// =================== CSV Export ===================

/** Sanitize a CSV field to prevent formula injection (=, +, -, @, \t, \r) */
function sanitizeCsvField(value: string): string {
  if (!value) return '';
  const dangerous = ['=', '+', '-', '@', '\t', '\r'];
  let sanitized = value.replace(/"/g, '""');
  if (dangerous.some(c => sanitized.startsWith(c))) {
    sanitized = `'${sanitized}`;
  }
  return `"${sanitized}"`;
}

// GET /api/payments/admin/export
router.get('/export', async (_req: Request, res: Response, next: NextFunction) => {
  try {
    const { prisma } = await import('../../config/database');
    const orders = await prisma.order.findMany({
      where: { status: 'COMPLETED' },
      include: { product: { select: { title: true } } },
      orderBy: { createdAt: 'desc' },
    });

    const lines = ['Date,Type,Amount (CAD),Buyer Email,Buyer Name,Product,Status'];
    for (const o of orders) {
      lines.push([
        o.createdAt.toISOString(),
        o.type,
        (o.amountCAD / 100).toFixed(2),
        sanitizeCsvField(o.buyerEmail || ''),
        sanitizeCsvField(o.buyerName || ''),
        sanitizeCsvField(o.product?.title || ''),
        o.status,
      ].join(','));
    }

    res.setHeader('Content-Type', 'text/csv');
    res.setHeader('Content-Disposition', 'attachment; filename=payments-export.csv');
    res.send(lines.join('\n'));
  } catch (err) {
    next(err);
  }
});

export { router as paymentsAdminRouter };
