/**
 * Admin API Routes — Audit Log + Data Cleanup
 *
 * GET  /api/admin/audit-log         — paginated, filtered list
 * GET  /api/admin/audit-log/export  — CSV download of filtered results
 * DELETE /api/admin/cleanup/:target  — preview / delete old data
 *
 * Both endpoints require authentication + admin:access permission.
 *
 * Register in app.ts:
 *   import adminRoutes from './routes/admin.routes';
 *   app.use('/api/admin', adminRoutes);
 */

import { Router, Request, Response } from 'express';
import { z } from 'zod';
import axios from 'axios';
import { authenticate } from '../middleware/auth.middleware';
import { requirePermission } from '../middleware/rbac.middleware';
import { auditExport } from '../middleware/audit.middleware';
import auditService, { AuditAction, AuditResourceType, AuditFilters } from '../services/audit.service';
import cleanupService from '../services/cleanup.service';
import userService from '../services/user.service';
import pool from '../config/database';
import logger from '../utils/logger';

const router = Router();

// ---------------------------------------------------------------------------
// Input validation schemas (Zod)
// ---------------------------------------------------------------------------

const auditQuerySchema = z.object({
  userId:       z.string().uuid().optional(),
  action:       z.union([
    z.nativeEnum(Object.fromEntries(
      Object.entries(AuditAction).map(([k, v]) => [k, v])
    ) as Record<string, string>),
    z.array(z.string()),
  ]).optional(),
  resourceType: z.union([
    z.string(),
    z.array(z.string()),
  ]).optional(),
  resourceId:   z.string().optional(),
  dateFrom:     z.string().datetime({ offset: true }).optional(),
  dateTo:       z.string().datetime({ offset: true }).optional(),
  page:         z.coerce.number().int().positive().default(1),
  pageSize:     z.coerce.number().int().min(1).max(200).default(25),
});

// ---------------------------------------------------------------------------
// Helper — parse and validate query string
// ---------------------------------------------------------------------------

function parseAuditQuery(query: Record<string, unknown>): AuditFilters {
  const parsed = auditQuerySchema.parse(query);

  // Normalise action to array of AuditAction
  const actions = parsed.action
    ? (Array.isArray(parsed.action) ? parsed.action : [parsed.action]) as AuditAction[]
    : undefined;

  // Normalise resourceType to array of AuditResourceType
  const resourceTypes = parsed.resourceType
    ? (Array.isArray(parsed.resourceType)
        ? parsed.resourceType
        : [parsed.resourceType]) as AuditResourceType[]
    : undefined;

  return {
    userId:       parsed.userId,
    action:       actions && actions.length === 1 ? actions[0] : actions,
    resourceType: resourceTypes && resourceTypes.length === 1
      ? resourceTypes[0]
      : resourceTypes,
    resourceId:   parsed.resourceId,
    dateFrom:     parsed.dateFrom ? new Date(parsed.dateFrom) : undefined,
    dateTo:       parsed.dateTo   ? new Date(parsed.dateTo)   : undefined,
    page:         parsed.page,
    pageSize:     parsed.pageSize,
  };
}

// ---------------------------------------------------------------------------
// GET /api/admin/audit-log
// ---------------------------------------------------------------------------

router.get(
  '/audit-log',
  authenticate,
  requirePermission('admin:view'),
  async (req: Request, res: Response): Promise<void> => {
    try {
      const filters = parseAuditQuery(req.query as Record<string, unknown>);

      const result = await auditService.getAuditLog(filters);

      res.status(200).json({
        success: true,
        data: result,
      });
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          message: 'Invalid query parameters',
          errors:  error.issues,
        });
        return;
      }

      logger.error('Failed to fetch audit log', { error });
      res.status(500).json({
        success: false,
        message: 'Failed to fetch audit log',
      });
    }
  }
);

// ---------------------------------------------------------------------------
// GET /api/admin/audit-log/export
// ---------------------------------------------------------------------------

router.get(
  '/audit-log/export',
  authenticate,
  requirePermission('admin:view'),
  async (req: Request, res: Response): Promise<void> => {
    try {
      // For CSV exports we fetch up to 10,000 rows (no pagination).
      const filters = parseAuditQuery(req.query as Record<string, unknown>);
      const exportFilters: AuditFilters = {
        ...filters,
        page:     1,
        pageSize: 10_000,
      };

      // Audit the export action itself before streaming the response
      auditExport(req, AuditResourceType.SYSTEM, {
        export_format: 'csv',
        filters:       JSON.stringify(exportFilters),
      });

      const result = await auditService.getAuditLog(exportFilters);
      const csv    = auditService.entriesToCsv(result.entries);

      const filename = `audit_log_${new Date().toISOString().replace(/[:.]/g, '-')}.csv`;

      res.setHeader('Content-Type', 'text/csv; charset=utf-8');
      res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
      // Add BOM for Excel UTF-8 compatibility
      res.send('\uFEFF' + csv);
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          message: 'Invalid query parameters',
          errors:  error.issues,
        });
        return;
      }

      logger.error('Failed to export audit log', { error });
      res.status(500).json({
        success: false,
        message: 'Failed to export audit log',
      });
    }
  }
);

// ---------------------------------------------------------------------------
// FDISK Sync proxy — forwards to the fdisk-sync sidecar service
// ---------------------------------------------------------------------------

const FDISK_SYNC_URL = process.env.FDISK_SYNC_URL ?? '';

router.get(
  '/fdisk-sync/logs',
  authenticate,
  requirePermission('admin:view'),
  async (_req: Request, res: Response): Promise<void> => {
    if (!FDISK_SYNC_URL) {
      res.status(503).json({ success: false, message: 'FDISK sync service not configured' });
      return;
    }
    try {
      const response = await axios.get(`${FDISK_SYNC_URL}/logs`, { timeout: 5000 });
      res.json({ success: true, data: response.data });
    } catch {
      res.status(502).json({ success: false, message: 'Could not reach sync service' });
    }
  }
);

router.post(
  '/fdisk-sync/trigger',
  authenticate,
  requirePermission('admin:view'),
  async (req: Request, res: Response): Promise<void> => {
    if (!FDISK_SYNC_URL) {
      res.status(503).json({ success: false, message: 'FDISK sync service not configured' });
      return;
    }
    try {
      const response = await axios.post(`${FDISK_SYNC_URL}/trigger`, req.body, { timeout: 5000 });
      res.json({ success: true, data: response.data });
    } catch (err: unknown) {
      if (axios.isAxiosError(err) && err.response?.status === 409) {
        res.status(409).json({ success: false, message: 'Sync already in progress' });
        return;
      }
      res.status(502).json({ success: false, message: 'Could not reach sync service' });
    }
  }
);

// ---------------------------------------------------------------------------
// Cleanup / Data Management endpoints
// ---------------------------------------------------------------------------

const cleanupBodySchema = z.object({
  olderThanDays: z.number().int().min(1).max(3650),
  confirm:       z.boolean().optional().default(false),
});

type CleanupTarget = 'notifications' | 'audit-log' | 'events' | 'bookings' | 'orders' | 'vehicle-history' | 'equipment-history' | 'checklist-history';

const CLEANUP_TARGETS: Record<CleanupTarget, (days: number, confirm: boolean) => Promise<{ count: number; deleted: boolean }>> = {
  'notifications':     (d, c) => cleanupService.cleanupNotifications(d, c),
  'audit-log':         (d, c) => cleanupService.cleanupAuditLog(d, c),
  'events':            (d, c) => cleanupService.cleanupEvents(d, c),
  'bookings':          (d, c) => cleanupService.cleanupBookings(d, c),
  'orders':            (d, c) => cleanupService.cleanupOrders(d, c),
  'vehicle-history':   (d, c) => cleanupService.cleanupVehicleHistory(d, c),
  'equipment-history': (d, c) => cleanupService.cleanupEquipmentHistory(d, c),
  'checklist-history': (d, c) => cleanupService.cleanupChecklistHistory(d, c),
};

router.delete('/cleanup/reset-bestellungen', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-bestellungen'; return resetHandler(req, res); });
router.delete('/cleanup/reset-ausruestung-anfragen', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-ausruestung-anfragen'; return resetHandler(req, res); });
router.delete('/cleanup/reset-issues', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-issues'; return resetHandler(req, res); });
router.delete('/cleanup/reset-buchhaltung-transaktionen', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-buchhaltung-transaktionen'; return resetHandler(req, res); });
router.delete('/cleanup/reset-buchhaltung-konten', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-buchhaltung-konten'; return resetHandler(req, res); });
router.delete('/cleanup/reset-buchhaltung-bankkonten', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-buchhaltung-bankkonten'; return resetHandler(req, res); });
router.delete('/cleanup/reset-checklist-history', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-checklist-history'; return resetHandler(req, res); });
router.delete('/cleanup/reset-persoenliche-ausruestung', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'reset-persoenliche-ausruestung'; return resetHandler(req, res); });
router.delete('/cleanup/issues-all', authenticate, requirePermission('admin:write'), (req, res) => { req.params.resetTarget = 'issues-all'; return resetHandler(req, res); });

router.delete(
  '/cleanup/:target',
  authenticate,
  requirePermission('admin:write'),
  async (req: Request, res: Response): Promise<void> => {
    try {
      const target = req.params.target as CleanupTarget;
      const handler = CLEANUP_TARGETS[target];
      if (!handler) {
        res.status(400).json({ success: false, message: `Unknown cleanup target: ${target}` });
        return;
      }

      const { olderThanDays, confirm } = cleanupBodySchema.parse(req.body);
      const result = await handler(olderThanDays, confirm);

      res.json({ success: true, data: result });
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({ success: false, message: 'Invalid parameters', errors: error.issues });
        return;
      }
      logger.error('Cleanup failed', { error, target: req.params.target });
      res.status(500).json({ success: false, message: 'Cleanup failed' });
    }
  }
);

// ---------------------------------------------------------------------------
// Reset / Truncate endpoints (no olderThanDays, just ?confirm=true)
// ---------------------------------------------------------------------------

const RESET_TARGETS: Record<string, (confirm: boolean) => Promise<{ count: number; deleted: boolean }>> = {
  'reset-bestellungen':                  (c) => cleanupService.resetBestellungenSequence(c),
  'reset-ausruestung-anfragen':          (c) => cleanupService.resetAusruestungAnfragenSequence(c),
  'reset-issues':                        (c) => cleanupService.resetIssuesSequence(c),
  'issues-all':                          (c) => cleanupService.resetIssuesSequence(c),
  'reset-checklist-history':             (c) => cleanupService.resetChecklistHistory(c),
  'reset-buchhaltung-transaktionen':     (c) => cleanupService.resetBuchhaltungTransaktionen(c),
  'reset-buchhaltung-konten':            (c) => cleanupService.resetBuchhaltungKonten(c),
  'reset-buchhaltung-bankkonten':        (c) => cleanupService.resetBuchhaltungBankkonten(c),
  'reset-persoenliche-ausruestung':      (c) => cleanupService.resetPersoenlicheAusruestung(c),
};

const resetHandler = async (req: Request, res: Response): Promise<void> => {
  try {
    const target = req.params.resetTarget as string;
    const handler = RESET_TARGETS[target];
    if (!handler) {
      res.status(400).json({ success: false, message: `Unknown reset target: ${target}` });
      return;
    }
    const confirm = req.query.confirm === 'true';
    const result = await handler(confirm);
    res.json({ success: true, data: result });
  } catch (error) {
    logger.error('Reset failed', { error, target: req.params.resetTarget });
    res.status(500).json({ success: false, message: 'Reset failed' });
  }
};

// ---------------------------------------------------------------------------
// DELETE /api/admin/users/:userId/sync-data — selective sync data deletion
// ---------------------------------------------------------------------------

const syncDataBodySchema = z.object({
  types: z.array(z.enum(['profile', 'ausbildung', 'untersuchungen', 'fuehrerschein', 'befoerderungen'])).min(1),
});

const SYNC_TABLE_MAP: Record<string, string> = {
  profile:        'mitglieder_profile',
  ausbildung:     'ausbildungen',
  untersuchungen: 'untersuchungen',
  fuehrerschein:  'fahrgenehmigungen',
  befoerderungen: 'befoerderungen',
};

router.delete(
  '/users/:userId/sync-data',
  authenticate,
  requirePermission('admin:write'),
  async (req: Request, res: Response): Promise<void> => {
    try {
      const userId = req.params.userId;
      const { types } = syncDataBodySchema.parse(req.body);

      const client = await pool.connect();
      try {
        await client.query('BEGIN');
        const results: Record<string, number> = {};

        for (const type of types) {
          const table = SYNC_TABLE_MAP[type];
          if (!table) continue;
          const result = await client.query(
            `DELETE FROM ${table} WHERE user_id = $1`,
            [userId]
          );
          results[type] = result.rowCount ?? 0;
        }

        await client.query('COMMIT');
        logger.info('Admin deleted sync data', { userId, types, results, admin: req.user?.id });
        res.json({ success: true, data: results });
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({ success: false, message: 'Invalid parameters', errors: error.issues });
        return;
      }
      logger.error('Failed to delete sync data', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Löschen der Sync-Daten' });
    }
  }
);

// ---------------------------------------------------------------------------
// DELETE /api/admin/users/:userId/fdisk-data — purge FDISK-synced data
// ---------------------------------------------------------------------------

router.delete(
  '/users/:userId/fdisk-data',
  authenticate,
  requirePermission('admin:write'),
  async (req: Request, res: Response): Promise<void> => {
    const targetUserId = req.params.userId;
    const client = await pool.connect();
    try {
      await client.query('BEGIN');

      // Null out FDISK-synced profile fields
      const profileResult = await client.query(
        `UPDATE mitglieder_profile
            SET status = NULL,
                eintrittsdatum = NULL,
                austrittsdatum = NULL,
                geburtsdatum = NULL,
                geburtsort = NULL,
                geschlecht = NULL,
                beruf = NULL,
                wohnort = NULL,
                plz = NULL,
                dienstgrad = NULL,
                updated_at = NOW()
          WHERE user_id = $1`,
        [targetUserId]
      );

      const ausbildungen = await client.query(
        'DELETE FROM ausbildung WHERE user_id = $1',
        [targetUserId]
      );
      const befoerderungen = await client.query(
        'DELETE FROM befoerderungen WHERE user_id = $1',
        [targetUserId]
      );
      const untersuchungen = await client.query(
        'DELETE FROM untersuchungen WHERE user_id = $1',
        [targetUserId]
      );
      const fahrgenehmigungen = await client.query(
        'DELETE FROM fahrgenehmigungen WHERE user_id = $1',
        [targetUserId]
      );

      await client.query('COMMIT');

      logger.info('Admin purged FDISK data', { targetUserId, adminId: req.user?.id });

      res.json({
        success: true,
        data: {
          profileFieldsCleared: profileResult.rowCount ?? 0,
          ausbildungen: ausbildungen.rowCount ?? 0,
          befoerderungen: befoerderungen.rowCount ?? 0,
          untersuchungen: untersuchungen.rowCount ?? 0,
          fahrgenehmigungen: fahrgenehmigungen.rowCount ?? 0,
        },
      });
    } catch (error) {
      await client.query('ROLLBACK');
      logger.error('Failed to purge FDISK data', { error, targetUserId });
      res.status(500).json({ success: false, message: 'Fehler beim Löschen der FDISK-Daten' });
    } finally {
      client.release();
    }
  }
);

// ---------------------------------------------------------------------------
// POST /api/admin/users/:userId/purge-data — delete all user-associated data
// (keeps the users record, financial records, and audit log)
// ---------------------------------------------------------------------------

router.post(
  '/users/:userId/purge-data',
  authenticate,
  requirePermission('admin:write'),
  async (req: Request, res: Response): Promise<void> => {
    try {
      const targetUserId = req.params.userId as string;
      const requestingUserId = req.user!.id;

      const targetUser = await userService.findById(targetUserId);
      if (!targetUser) {
        res.status(404).json({ success: false, message: 'Benutzer nicht gefunden' });
        return;
      }

      const result = await userService.purgeUserData(targetUserId, requestingUserId);

      // Audit log
      await auditService.logAudit({
        user_id: requestingUserId,
        user_email: req.user!.email,
        action: AuditAction.DELETE,
        resource_type: AuditResourceType.USER,
        resource_id: targetUserId,
        old_value: { email: targetUser.email, name: targetUser.name },
        new_value: { purged_tables: result },
        ip_address: req.ip ?? null,
        user_agent: req.headers['user-agent'] ?? null,
        metadata: { operation: 'purge_user_data' },
      });

      res.json({ success: true, data: result });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Fehler beim Löschen der Benutzerdaten';
      if (message === 'Cannot purge your own data') {
        res.status(400).json({ success: false, message: 'Eigene Daten können nicht gelöscht werden' });
        return;
      }
      logger.error('Failed to purge user data', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Löschen der Benutzerdaten' });
    }
  }
);

export default router;
