import { Router, Request, Response } from 'express';
import { AdminRepository } from '../../database/repositories/admin-repo';
import { logger } from '../../utils/logger';
import { authenticateToken, requireRole, AuthRequest, generateToken } from '../middleware/auth';
import { cacheMiddleware } from '../middleware/cache';
import { appendCentralAudit } from '../central-audit';

const router: Router = Router();
const adminRepo = new AdminRepository();

// Authentication routes (public)
router.post('/auth/login', async (req: Request, res: Response) => {
  try {
    const { username, password } = req.body;

    if (!username || !password) {
      return res.status(400).json({ error: 'Username and password are required' });
    }

    const user = await adminRepo.getAdminUserByUsername(username);
    if (!user || !user.isActive) {
      return res.status(401).json({ error: 'Invalid credentials' });
    }

    const isValid = await adminRepo.verifyPassword(user, password);
    if (!isValid) {
      return res.status(401).json({ error: 'Invalid credentials' });
    }

    // Update last login
    await adminRepo.pool.query(
      `UPDATE admin_users SET last_login = NOW() WHERE id = $1`,
      [user.id]
    );

    // Generate token
    const token = generateToken(user.id!, user.username, user.role);

    res.json({
      token,
      user: {
        id: user.id,
        username: user.username,
        email: user.email,
        role: user.role,
      },
    });
  } catch (error) {
    logger.error('Login error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// All admin routes require authentication
router.use(authenticateToken);

// API Keys Management
router.get('/api-keys', requireRole('admin', 'super_admin', 'operator'), async (req: Request, res: Response) => {
  try {
    const provider = req.query.provider as string | undefined;
    const keys = await adminRepo.getApiKeys(provider);
    res.json({ apiKeys: keys });
  } catch (error) {
    logger.error('Error fetching API keys:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

router.post('/api-keys', requireRole('admin', 'super_admin'), async (req: AuthRequest, res: Response) => {
  try {
    const { provider, keyName, apiKey, rateLimitPerMinute, rateLimitPerDay, expiresAt } = req.body;

    if (!provider || !keyName || !apiKey) {
      return res.status(400).json({ error: 'Provider, keyName, and apiKey are required' });
    }

    // Simple encryption (in production, use proper encryption)
    const encrypted = Buffer.from(apiKey).toString('base64');

    const newKey = await adminRepo.createApiKey({
      provider,
      keyName,
      apiKeyEncrypted: encrypted,
      isActive: true,
      rateLimitPerMinute,
      rateLimitPerDay,
      expiresAt: expiresAt ? new Date(expiresAt) : undefined,
      createdBy: req.user?.username,
    });

    // Audit log
    await adminRepo.createAuditLog(
      req.user?.id || null,
      'create',
      'api_key',
      newKey.id || null,
      null,
      { provider, keyName },
      req.ip,
      req.get('user-agent')
    );
    appendCentralAudit({ employeeId: String(req.user?.id ?? req.user?.username ?? 'unknown'), action: 'create', permission: 'admin:action', resourceType: 'api_key', resourceId: String(newKey.id ?? ''), metadata: { provider, keyName }, ipAddress: req.ip, userAgent: req.get('user-agent') ?? undefined }).catch(() => {});

    res.status(201).json({ apiKey: { ...newKey, apiKeyEncrypted: undefined } });
  } catch (error) {
    logger.error('Error creating API key:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

router.put('/api-keys/:id', requireRole('admin', 'super_admin'), async (req: AuthRequest, res: Response) => {
  try {
    const id = parseInt(req.params.id, 10);
    const updates: { isActive?: boolean; rateLimitPerMinute?: number; expiresAt?: Date } = {};

    if (req.body.isActive !== undefined) updates.isActive = req.body.isActive;
    if (req.body.rateLimitPerMinute !== undefined) updates.rateLimitPerMinute = req.body.rateLimitPerMinute;
    if (req.body.expiresAt !== undefined) updates.expiresAt = new Date(req.body.expiresAt);

    const oldKey = await adminRepo.getApiKey(id);
    await adminRepo.updateApiKey(id, updates);

    // Audit log
    await adminRepo.createAuditLog(
      req.user?.id || null,
      'update',
      'api_key',
      id,
      oldKey as unknown as Record<string, unknown>,
      updates as unknown as Record<string, unknown>,
      req.ip,
      req.get('user-agent')
    );
    appendCentralAudit({ employeeId: String(req.user?.id ?? req.user?.username ?? 'unknown'), action: 'update', permission: 'admin:action', resourceType: 'api_key', resourceId: String(id), metadata: updates, ipAddress: req.ip, userAgent: req.get('user-agent') ?? undefined }).catch(() => {});

    res.json({ success: true });
  } catch (error) {
    logger.error('Error updating API key:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

router.delete('/api-keys/:id', requireRole('admin', 'super_admin'), async (req: AuthRequest, res: Response) => {
  try {
    const id = parseInt(req.params.id, 10);
    const oldKey = await adminRepo.getApiKey(id);

    await adminRepo.deleteApiKey(id);

    // Audit log
    await adminRepo.createAuditLog(
      req.user?.id || null,
      'delete',
      'api_key',
      id,
      oldKey as unknown as Record<string, unknown>,
      null,
      req.ip,
      req.get('user-agent')
    );
    appendCentralAudit({ employeeId: String(req.user?.id ?? req.user?.username ?? 'unknown'), action: 'delete', permission: 'admin:action', resourceType: 'api_key', resourceId: String(id), ipAddress: req.ip, userAgent: req.get('user-agent') ?? undefined }).catch(() => {});

    res.json({ success: true });
  } catch (error) {
    logger.error('Error deleting API key:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// API Endpoints Management
router.get('/endpoints', requireRole('admin', 'super_admin', 'operator', 'viewer'), async (req: Request, res: Response) => {
  try {
    const chainId = req.query.chainId ? parseInt(req.query.chainId as string, 10) : undefined;
    const endpointType = req.query.endpointType as string | undefined;
    const endpoints = await adminRepo.getEndpoints(chainId, endpointType);
    res.json({ endpoints });
  } catch (error) {
    logger.error('Error fetching endpoints:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

router.post('/endpoints', requireRole('admin', 'super_admin'), async (req: AuthRequest, res: Response) => {
  try {
    const {
      chainId,
      endpointType,
      endpointName,
      endpointUrl,
      isPrimary,
      requiresAuth,
      authType,
      authConfig,
      rateLimitPerMinute,
      timeoutMs,
    } = req.body;

    if (!chainId || !endpointType || !endpointName || !endpointUrl) {
      return res.status(400).json({ error: 'Missing required fields' });
    }

    const endpoint = await adminRepo.createEndpoint({
      chainId,
      endpointType,
      endpointName,
      endpointUrl,
      isPrimary: isPrimary || false,
      isActive: true,
      requiresAuth: requiresAuth || false,
      authType,
      authConfig,
      rateLimitPerMinute,
      timeoutMs: timeoutMs || 10000,
      healthCheckEnabled: true,
      createdBy: req.user?.username,
    });

    // Audit log
    await adminRepo.createAuditLog(
      req.user?.id || null,
      'create',
      'endpoint',
      endpoint.id || null,
      null,
      { chainId, endpointType, endpointName, endpointUrl },
      req.ip,
      req.get('user-agent')
    );
    appendCentralAudit({ employeeId: String(req.user?.id ?? req.user?.username ?? 'unknown'), action: 'create', permission: 'admin:action', resourceType: 'endpoint', resourceId: String(endpoint.id ?? ''), metadata: { chainId, endpointType, endpointName, endpointUrl }, ipAddress: req.ip, userAgent: req.get('user-agent') ?? undefined }).catch(() => {});

    res.status(201).json({ endpoint });
  } catch (error) {
    logger.error('Error creating endpoint:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

router.put('/endpoints/:id', requireRole('admin', 'super_admin'), async (req: AuthRequest, res: Response) => {
  try {
    const id = parseInt(req.params.id, 10);
    const updates: { endpointUrl?: string; isActive?: boolean; isPrimary?: boolean } = {};

    if (req.body.endpointUrl !== undefined) updates.endpointUrl = req.body.endpointUrl;
    if (req.body.isActive !== undefined) updates.isActive = req.body.isActive;
    if (req.body.isPrimary !== undefined) updates.isPrimary = req.body.isPrimary;

    await adminRepo.updateEndpoint(id, updates);

    res.json({ success: true });
  } catch (error) {
    logger.error('Error updating endpoint:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// DEX Factory Management
router.get('/dex-factories', requireRole('admin', 'super_admin', 'operator', 'viewer'), async (req: Request, res: Response) => {
  try {
    const chainId = req.query.chainId ? parseInt(req.query.chainId as string, 10) : undefined;
    const factories = await adminRepo.getDexFactories(chainId);
    res.json({ factories });
  } catch (error) {
    logger.error('Error fetching DEX factories:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

router.post('/dex-factories', requireRole('admin', 'super_admin'), async (req: AuthRequest, res: Response) => {
  try {
    const {
      chainId,
      dexType,
      factoryAddress,
      routerAddress,
      poolManagerAddress,
      startBlock,
      description,
    } = req.body;

    if (!chainId || !dexType || !factoryAddress) {
      return res.status(400).json({ error: 'Missing required fields' });
    }

    const factory = await adminRepo.createDexFactory({
      chainId,
      dexType,
      factoryAddress,
      routerAddress,
      poolManagerAddress,
      startBlock: startBlock || 0,
      isActive: true,
      description,
      createdBy: req.user?.username,
    });

    // Audit log
    await adminRepo.createAuditLog(
      req.user?.id || null,
      'create',
      'dex_factory',
      factory.id || null,
      null,
      { chainId, dexType, factoryAddress },
      req.ip,
      req.get('user-agent')
    );
    appendCentralAudit({ employeeId: String(req.user?.id ?? req.user?.username ?? 'unknown'), action: 'create', permission: 'admin:action', resourceType: 'dex_factory', resourceId: String(factory.id ?? ''), metadata: { chainId, dexType, factoryAddress }, ipAddress: req.ip, userAgent: req.get('user-agent') ?? undefined }).catch(() => {});

    res.status(201).json({ factory });
  } catch (error) {
    logger.error('Error creating DEX factory:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// Service Status
router.get('/status', requireRole('admin', 'super_admin', 'operator', 'viewer'), cacheMiddleware(30 * 1000), async (req: Request, res: Response) => {
  try {
    const [apiKeys, endpoints, factories] = await Promise.all([
      adminRepo.getApiKeys(),
      adminRepo.getEndpoints(),
      adminRepo.getDexFactories(),
    ]);

    res.json({
      status: 'operational',
      stats: {
        apiKeys: {
          total: apiKeys.length,
          active: apiKeys.filter((k) => k.isActive).length,
        },
        endpoints: {
          total: endpoints.length,
          active: endpoints.filter((e) => e.isActive).length,
        },
        factories: {
          total: factories.length,
          active: factories.filter((f) => f.isActive).length,
        },
      },
    });
  } catch (error) {
    logger.error('Error fetching status:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// Audit Log
router.get('/audit-log', requireRole('admin', 'super_admin'), async (req: Request, res: Response) => {
  try {
    const limit = parseInt(req.query.limit as string, 10) || 100;
    const offset = parseInt(req.query.offset as string, 10) || 0;

    const result = await adminRepo.pool.query(
      `SELECT al.*, au.username
       FROM admin_audit_log al
       LEFT JOIN admin_users au ON al.user_id = au.id
       ORDER BY al.created_at DESC
       LIMIT $1 OFFSET $2`,
      [limit, offset]
    );

    res.json({
      logs: result.rows.map((row) => ({
        id: row.id,
        username: row.username,
        action: row.action,
        resourceType: row.resource_type,
        resourceId: row.resource_id,
        oldValues: row.old_values,
        newValues: row.new_values,
        ipAddress: row.ip_address,
        userAgent: row.user_agent,
        createdAt: row.created_at,
      })),
      pagination: {
        limit,
        offset,
        count: result.rows.length,
      },
    });
  } catch (error) {
    logger.error('Error fetching audit log:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

export default router;
