import fs from "node:fs";
import path from "node:path";
import { settings } from "./config.js";

export const DEVICE_MODES = new Set(["direct", "vpn", "rules", "block", "bypass"]);
export const DEFAULT_DEVICE_MODES = new Set(["direct", "vpn", "block"]);
export const DEFAULT_DEVICE_MODE = "vpn";
export const DEFAULT_PROXY_MODE = "vpn";
export const TPROXY_INBOUND = "tproxy-in";
export const MIXED_INBOUND = "mixed-in";

const IPISH_RE = /^[\.\d:/]+$/;

function readJson(filePath, fallback) {
  try {
    if (!fs.existsSync(filePath)) return fallback;
    return JSON.parse(fs.readFileSync(filePath, "utf8"));
  } catch {
    return fallback;
  }
}

function writeJson(filePath, value) {
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, JSON.stringify(value, null, 2), "utf8");
}

function normalizeDeviceMode(mode, fallback = "rules") {
  const value = String(mode || "").trim().toLowerCase();
  return DEVICE_MODES.has(value) ? value : fallback;
}

function normalizeDefaultMode(mode) {
  const value = String(mode || "").trim().toLowerCase();
  return DEFAULT_DEVICE_MODES.has(value) ? value : DEFAULT_DEVICE_MODE;
}

function normalizeProxyMode(mode) {
  const value = String(mode || "").trim().toLowerCase();
  return DEFAULT_DEVICE_MODES.has(value) ? value : DEFAULT_PROXY_MODE;
}

function normalizeIp(ip) {
  const value = String(ip || "").trim();
  return value && IPISH_RE.test(value) ? value : "";
}

function normalizeMac(mac) {
  return String(mac || "").trim();
}

function fromLegacyDeviceRules(input) {
  const rules = Array.isArray(input) ? input : [];
  const devices = [];

  for (const rule of rules) {
    const sourceIps = Array.isArray(rule?.sourceIps) ? rule.sourceIps : [];
    const mode = normalizeDeviceMode(rule?.outbound, "direct");
    sourceIps.forEach((sourceIp, ipIndex) => {
      const ip = normalizeIp(sourceIp);
      if (!ip) return;
      devices.push({
        id: String(rule.id || `dev-${devices.length}`) + `-${ipIndex}`,
        name: String(rule.name || `Устройство ${devices.length + 1}`).trim(),
        enabled: rule.enabled !== false,
        ip,
        mac: "",
        mode,
        lastSeen: null,
      });
    });
  }

  return {
    defaultTransparentMode: DEFAULT_DEVICE_MODE,
    proxyDefaultMode: DEFAULT_PROXY_MODE,
    devices,
  };
}

export function normalizeDeviceProfiles(input) {
  const raw =
    input && typeof input === "object" && !Array.isArray(input)
      ? input
      : { devices: input };
  const rawDevices = Array.isArray(raw.devices) ? raw.devices : [];

  return {
    defaultTransparentMode: normalizeDefaultMode(
      raw.defaultTransparentMode || raw.defaultMode,
    ),
    proxyDefaultMode: normalizeProxyMode(raw.proxyDefaultMode),
    devices: rawDevices.map((device, index) => ({
      id: String(device.id || `dev-${Date.now()}-${index}`),
      name: String(device.name || `Устройство ${index + 1}`).trim(),
      enabled: device.enabled !== false,
      ip: normalizeIp(device.ip || device.sourceIp),
      mac: normalizeMac(device.mac),
      mode: normalizeDeviceMode(device.mode || device.outbound, "rules"),
      lastSeen: device.lastSeen || null,
    })),
  };
}

export function readDeviceProfiles() {
  if (fs.existsSync(settings.devicesPath)) {
    return normalizeDeviceProfiles(readJson(settings.devicesPath, null));
  }

  if (fs.existsSync(settings.deviceRulesPath)) {
    return normalizeDeviceProfiles(
      fromLegacyDeviceRules(readJson(settings.deviceRulesPath, [])),
    );
  }

  return {
    defaultTransparentMode: DEFAULT_DEVICE_MODE,
    proxyDefaultMode: DEFAULT_PROXY_MODE,
    devices: [],
  };
}

export function writeDeviceProfiles(value) {
  const normalized = normalizeDeviceProfiles(value);
  writeJson(settings.devicesPath, normalized);
  return normalized;
}

export function normalizeCidr(ip) {
  const value = normalizeIp(ip);
  if (!value) return "";
  return value.includes("/") ? value : `${value}/32`;
}

export function deviceCidrs(devices, modes) {
  const allowedModes = new Set(Array.isArray(modes) ? modes : [modes]);
  return (Array.isArray(devices) ? devices : [])
    .filter((device) => device.enabled !== false && allowedModes.has(device.mode))
    .map((device) => normalizeCidr(device.ip))
    .filter(Boolean);
}

export function legacyDeviceRulesFromProfiles(profiles) {
  const { devices } = normalizeDeviceProfiles(profiles);
  return devices.map((device) => ({
    id: device.id,
    name: device.name,
    enabled: device.enabled,
    sourceIps: device.ip ? [device.ip] : [],
    outbound: device.mode === "rules" ? "direct" : device.mode,
  }));
}
