import { Router, type IRouter } from 'express';
import {
  users, auditLog, indicatorConfigs, filterConfigs,
  getNextUserId, getNextConfigId, addAuditEvent,
  addUser, updateUser, removeUser,
  addIndicatorConfig, updateIndicatorConfig, removeIndicatorConfig, reorderIndicatorConfigs,
  addFilterConfig, updateFilterConfig, removeFilterConfig, reorderFilterConfigs,
  type UserRecord, type IndicatorConfig, type FilterConfig,
} from '../data/store';
import { requireAuth, requireAdmin } from '../middlewares/auth';

const router: IRouter = Router();
router.use('/admin', requireAuth);

// ── Audit log ────────────────────────────────────────────────────────────────
router.get('/admin/audit-log', (_req, res) => {
  res.json(auditLog);
});

// ── Users ────────────────────────────────────────────────────────────────────
router.get('/admin/users', (_req, res) => {
  res.json(users.map(({ password: _pw, ...u }) => u));
});

router.post('/admin/users', requireAdmin, async (req, res) => {
  const { username, password, name, email, role, status } = req.body as Partial<UserRecord>;
  if (!username || !password || !name || !email || !role) {
    return res.status(400).json({ error: 'username, password, name, email and role are required' });
  }
  if (users.find((u) => u.username === username)) {
    return res.status(409).json({ error: 'Username already exists' });
  }
  const newUserRecord: UserRecord = {
    id: getNextUserId(),
    username, password, name, email,
    role: role as UserRecord['role'],
    status: (status as UserRecord['status']) ?? 'Active',
    lastLogin: 'Not yet',
  };
  await addUser(newUserRecord);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  await addAuditEvent('Created user', username, actor,
    `Created ${newUserRecord.role} account with status ${newUserRecord.status}`,
    { userId: newUserRecord.id, role: newUserRecord.role, status: newUserRecord.status, email: newUserRecord.email });
  const { password: _pw, ...publicUser } = newUserRecord;
  return res.status(201).json(publicUser);
});

router.patch('/admin/users/:id', requireAdmin, async (req, res) => {
  const id = Number(req.params.id);
  const user = users.find((u) => u.id === id);
  if (!user) return res.status(404).json({ error: 'User not found' });
  const previousUser = { ...user };
  const { name, email, role, status, password } = req.body as Partial<UserRecord>;
  if (name) user.name = name;
  if (email) user.email = email;
  if (role) user.role = role as UserRecord['role'];
  if (status) user.status = status as UserRecord['status'];
  if (password) user.password = password;
  await updateUser(user);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  const changedUserFields: string[] = [];
  if (previousUser.name !== user.name) changedUserFields.push(`name: "${previousUser.name}" → "${user.name}"`);
  if (previousUser.email !== user.email) changedUserFields.push(`email: ${previousUser.email} → ${user.email}`);
  if (previousUser.role !== user.role) changedUserFields.push(`role: ${previousUser.role} → ${user.role}`);
  if (previousUser.status !== user.status) changedUserFields.push(`status: ${previousUser.status} → ${user.status}`);
  if (previousUser.password !== user.password) changedUserFields.push('password changed');
  if (changedUserFields.length > 0) {
    await addAuditEvent('Updated user', user.username, actor, changedUserFields.join('; '),
      { userId: user.id, changedFields: changedUserFields });
  }
  const { password: _pw, ...publicUser } = user;
  return res.json(publicUser);
});

router.delete('/admin/users/:id', requireAdmin, async (req, res) => {
  const id = Number(req.params.id);
  if (id === req.session!.userId) return res.status(400).json({ error: 'Cannot delete your own account' });
  const user = users.find((u) => u.id === id);
  if (!user) return res.status(404).json({ error: 'User not found' });
  await removeUser(id);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  await addAuditEvent('Deleted user', user.username, actor,
    `Deleted ${user.role} account (${user.status})`,
    { userId: user.id, role: user.role, status: user.status, email: user.email });
  return res.json({ ok: true });
});

// ── Indicator configs ─────────────────────────────────────────────────────────
router.get('/admin/indicator-configs', (_req, res) => {
  res.json([...indicatorConfigs].sort((a, b) => a.order - b.order));
});

router.post('/admin/indicator-configs', requireAdmin, async (req, res) => {
  const body = req.body as Partial<IndicatorConfig>;
  if (!body.label || !body.layerId || !body.column || !body.aggregation) {
    return res.status(400).json({ error: 'label, layerId, column, aggregation required' });
  }
  const cfg: IndicatorConfig = {
    id: getNextConfigId(),
    label: body.label,
    layerId: body.layerId,
    column: body.column,
    aggregation: body.aggregation as IndicatorConfig['aggregation'],
    format: (body.format as IndicatorConfig['format']) ?? 'number',
    color: body.color ?? '#2563eb',
    icon: body.icon ?? 'bar-chart',
    order: indicatorConfigs.length + 1,
    enabled: body.enabled ?? true,
  };
  await addIndicatorConfig(cfg);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  await addAuditEvent('Created indicator', body.label, actor,
    `aggregation: ${cfg.aggregation}, column: "${cfg.column}", format: ${cfg.format}`,
    { indicatorId: cfg.id, layerId: cfg.layerId, column: cfg.column, aggregation: cfg.aggregation, format: cfg.format, enabled: cfg.enabled });
  return res.status(201).json(cfg);
});

router.post('/admin/indicator-configs/reorder', requireAdmin, async (req, res) => {
  const { ids } = req.body as { ids: string[] };
  if (!Array.isArray(ids)) return res.status(400).json({ error: 'ids array required' });
  await reorderIndicatorConfigs(ids);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  await addAuditEvent('Reordered indicators', 'Dashboard indicators', actor,
    `New order contains ${ids.length} indicators`, { indicatorIds: ids, count: ids.length });
  return res.json({ ok: true });
});

router.patch('/admin/indicator-configs/:id', requireAdmin, async (req, res) => {
  const cfg = indicatorConfigs.find((c) => c.id === req.params.id);
  if (!cfg) return res.status(404).json({ error: 'Not found' });
  const body = req.body as Partial<IndicatorConfig>;
  // Collect diff before mutating
  const changes: string[] = [];
  if (body.label !== undefined && body.label !== cfg.label) changes.push(`label: "${body.label}"`);
  if (body.aggregation !== undefined && body.aggregation !== cfg.aggregation) changes.push(`aggregation: ${body.aggregation}`);
  if (body.column !== undefined && body.column !== cfg.column) changes.push(`column: "${body.column}"`);
  if (body.format !== undefined && body.format !== cfg.format) changes.push(`format: ${body.format}`);
  if (body.enabled !== undefined && body.enabled !== cfg.enabled) changes.push(`enabled: ${body.enabled}`);
  if (body.color !== undefined && body.color !== cfg.color) changes.push(`color: ${body.color}`);
  if (body.layerId !== undefined && body.layerId !== cfg.layerId) changes.push('layer changed');
  if (body.icon !== undefined && body.icon !== cfg.icon) changes.push(`icon: ${body.icon}`);
  if (body.order !== undefined && body.order !== cfg.order) changes.push(`order: ${body.order}`);

  if (body.label !== undefined) cfg.label = body.label;
  if (body.layerId !== undefined) cfg.layerId = body.layerId;
  if (body.column !== undefined) cfg.column = body.column;
  if (body.aggregation !== undefined) cfg.aggregation = body.aggregation as IndicatorConfig['aggregation'];
  if (body.format !== undefined) cfg.format = body.format as IndicatorConfig['format'];
  if (body.color !== undefined) cfg.color = body.color;
  if (body.icon !== undefined) cfg.icon = body.icon;
  if (body.order !== undefined) cfg.order = body.order;
  if (body.enabled !== undefined) cfg.enabled = body.enabled;
  await updateIndicatorConfig(cfg);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  if (changes.length > 0) {
    await addAuditEvent('Updated indicator', cfg.label, actor, changes.join('; '),
      { indicatorId: cfg.id, changedFields: changes });
  }
  return res.json(cfg);
});

router.delete('/admin/indicator-configs/:id', requireAdmin, async (req, res) => {
  const cfg = indicatorConfigs.find((c) => c.id === req.params.id);
  if (!cfg) return res.status(404).json({ error: 'Not found' });
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  await addAuditEvent('Deleted indicator', cfg.label, actor,
    `was: ${cfg.aggregation} of "${cfg.column}", format: ${cfg.format}`,
    { indicatorId: cfg.id, layerId: cfg.layerId, column: cfg.column, aggregation: cfg.aggregation, format: cfg.format });
  await removeIndicatorConfig(cfg.id);
  return res.json({ ok: true });
});

// ── Filter configs ────────────────────────────────────────────────────────────
router.get('/admin/filter-configs', (_req, res) => {
  res.json([...filterConfigs].sort((a, b) => a.order - b.order));
});

router.post('/admin/filter-configs', requireAdmin, async (req, res) => {
  const body = req.body as Partial<FilterConfig>;
  if (!body.label || !body.layerId || !body.column || !body.type) {
    return res.status(400).json({ error: 'label, layerId, column, type required' });
  }
  const cfg: FilterConfig = {
    id: getNextConfigId(),
    label: body.label,
    layerId: body.layerId,
    column: body.column,
    type: body.type as FilterConfig['type'],
    placeholder: body.placeholder ?? '',
    order: filterConfigs.length + 1,
    enabled: body.enabled ?? true,
    joins: Array.isArray(body.joins) ? body.joins : [],
  };
  await addFilterConfig(cfg);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  await addAuditEvent('Created filter', body.label, actor,
    `type: ${cfg.type}, column: "${cfg.column}"`,
    { slicerId: cfg.id, layerId: cfg.layerId, column: cfg.column, type: cfg.type, enabled: cfg.enabled, joinCount: cfg.joins.length });
  return res.status(201).json(cfg);
});

router.post('/admin/filter-configs/reorder', requireAdmin, async (req, res) => {
  const { ids } = req.body as { ids: string[] };
  if (!Array.isArray(ids)) return res.status(400).json({ error: 'ids array required' });
  await reorderFilterConfigs(ids);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  await addAuditEvent('Reordered slicers', 'Dashboard slicers', actor,
    `New order contains ${ids.length} slicers`, { slicerIds: ids, count: ids.length });
  return res.json({ ok: true });
});

router.patch('/admin/filter-configs/:id', requireAdmin, async (req, res) => {
  const cfg = filterConfigs.find((c) => c.id === req.params.id);
  if (!cfg) return res.status(404).json({ error: 'Not found' });
  const body = req.body as Partial<FilterConfig>;
  const changes: string[] = [];
  if (body.label !== undefined && body.label !== cfg.label) changes.push(`label: "${body.label}"`);
  if (body.type !== undefined && body.type !== cfg.type) changes.push(`type: ${body.type}`);
  if (body.column !== undefined && body.column !== cfg.column) changes.push(`column: "${body.column}"`);
  if (body.enabled !== undefined && body.enabled !== cfg.enabled) changes.push(`enabled: ${body.enabled}`);
  if (body.layerId !== undefined && body.layerId !== cfg.layerId) changes.push('layer changed');
  if (body.placeholder !== undefined && body.placeholder !== cfg.placeholder) changes.push(`placeholder: "${body.placeholder}"`);
  if (body.order !== undefined && body.order !== cfg.order) changes.push(`order: ${body.order}`);
  if (Array.isArray(body.joins) && JSON.stringify(body.joins) !== JSON.stringify(cfg.joins)) changes.push('joins changed');

  if (body.label !== undefined) cfg.label = body.label;
  if (body.layerId !== undefined) cfg.layerId = body.layerId;
  if (body.column !== undefined) cfg.column = body.column;
  if (body.type !== undefined) cfg.type = body.type as FilterConfig['type'];
  if (body.placeholder !== undefined) cfg.placeholder = body.placeholder;
  if (body.order !== undefined) cfg.order = body.order;
  if (body.enabled !== undefined) cfg.enabled = body.enabled;
  if (Array.isArray(body.joins)) cfg.joins = body.joins;
  await updateFilterConfig(cfg);
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  if (changes.length > 0) {
    await addAuditEvent('Updated filter', cfg.label, actor, changes.join('; '),
      { slicerId: cfg.id, changedFields: changes });
  }
  return res.json(cfg);
});

router.delete('/admin/filter-configs/:id', requireAdmin, async (req, res) => {
  const cfg = filterConfigs.find((c) => c.id === req.params.id);
  if (!cfg) return res.status(404).json({ error: 'Not found' });
  const actor = users.find((u) => u.id === req.session!.userId)?.name ?? 'Admin';
  await addAuditEvent('Deleted filter', cfg.label, actor,
    `was: ${cfg.type} on column "${cfg.column}"`,
    { slicerId: cfg.id, layerId: cfg.layerId, column: cfg.column, type: cfg.type, joinCount: cfg.joins.length });
  await removeFilterConfig(cfg.id);
  return res.json({ ok: true });
});

export default router;
