import { isIP } from 'node:net';
import { Router, type Request } from 'express';
import { z } from 'zod';
import { requireAdmin, requireAuth } from './auth';
import { config } from './config';
import { pool } from './db';
import { decryptAccessAddress, encryptAccessAddress, hashAccessAddress } from './privacy';

export const accessLogsRouter = Router();

const cleanAddress = (value: string) => value.split(',')[0].trim().replace(/^::ffff:/, '') || 'unknown';
const privateAddress = (value: string) => {
  if (value === 'unknown' || value === '::1') return true;
  if (isIP(value) === 4) return /^(10\.|127\.|192\.168\.|169\.254\.)/.test(value)
    || /^172\.(1[6-9]|2\d|3[01])\./.test(value);
  return /^(fc|fd|fe80)/i.test(value);
};

const headerValue = (request: Request, names: string[]) => {
  for (const name of names) {
    const value = request.header(name)?.trim();
    if (value) {
      try { return decodeURIComponent(value).slice(0, 120); }
      catch { return value.slice(0, 120); }
    }
  }
  return null;
};

const clientDetails = (userAgent: string) => {
  const browser = /Edg\//.test(userAgent) ? 'Edge' : /Chrome\//.test(userAgent) ? 'Chrome'
    : /Firefox\//.test(userAgent) ? 'Firefox' : /Safari\//.test(userAgent) ? 'Safari' : 'غير معروف';
  const operatingSystem = /Android/.test(userAgent) ? 'Android' : /iPhone|iPad/.test(userAgent) ? 'iOS'
    : /Windows/.test(userAgent) ? 'Windows' : /Mac OS/.test(userAgent) ? 'macOS'
      : /Linux/.test(userAgent) ? 'Linux' : 'غير معروف';
  const deviceType = /Mobile|Android|iPhone/.test(userAgent) ? 'هاتف'
    : /iPad|Tablet/.test(userAgent) ? 'جهاز لوحي' : 'حاسوب';
  return { browser, operatingSystem, deviceType };
};

export async function recordUserAccess(request: Request, userId: string) {
  const address = cleanAddress(request.ip || request.socket.remoteAddress || 'unknown');
  const userAgent = request.header('user-agent')?.slice(0, 600) ?? '';
  const details = clientDetails(userAgent);
  const trustedGeo = config.trustProxyHops > 0;
  await pool.query(
    `INSERT INTO user_access_logs (user_id,ip_encrypted,ip_hash,ip_version,is_private,
       country,region,city,user_agent,device_type,browser,operating_system)
     VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)`,
    [userId, encryptAccessAddress(address), hashAccessAddress(address), isIP(address) === 6 ? 'IPv6' : 'IPv4',
      privateAddress(address), trustedGeo ? headerValue(request, ['cf-ipcountry', 'x-vercel-ip-country']) : null,
      trustedGeo ? headerValue(request, ['x-vercel-ip-country-region', 'cf-region']) : null,
      trustedGeo ? headerValue(request, ['x-vercel-ip-city', 'cf-ipcity']) : null,
      userAgent, details.deviceType, details.browser, details.operatingSystem],
  );
}

accessLogsRouter.get('/users/:id/access-logs', requireAuth, requireAdmin, async (request, response) => {
  const userId = z.uuid().safeParse(request.params.id);
  if (!userId.success) { response.status(400).json({ error: 'Invalid user ID' }); return; }
  const result = await pool.query<{
    id: number; ipEncrypted: string; ipVersion: string; isPrivate: boolean; country: string | null;
    region: string | null; city: string | null; deviceType: string; browser: string;
    operatingSystem: string; createdAt: Date;
  }>(
    `SELECT id,ip_encrypted AS "ipEncrypted",ip_version AS "ipVersion",is_private AS "isPrivate",
       country,region,city,device_type AS "deviceType",browser,operating_system AS "operatingSystem",
       created_at AS "createdAt" FROM user_access_logs WHERE user_id=$1 ORDER BY created_at DESC LIMIT 200`,
    [userId.data],
  );
  response.json({ logs: result.rows.map((item) => ({
    ...item, ipAddress: decryptAccessAddress(item.ipEncrypted), ipEncrypted: undefined,
  })) });
});
