/**
 * gatewayService.js
 * All business logic + validation — zero external dependencies.
 * Uses only Node.js built-in Date object instead of dayjs.
 */

const GatewayModel = require("../model/gatewayModel");

// ─── Date Helpers (no dayjs needed) ──────────────────────────────────────────

function toISO(val) {
  if (!val) return null;
  return new Date(val).toISOString();
}

function isValidDate(str) {
  if (!str) return false;
  const d = new Date(str);
  return !isNaN(d.getTime());
}

function isValidURL(str) {
  try { new URL(str); return true; } catch { return false; }
}

function nowUTC() {
  return new Date();
}

// ─── Live Status Resolver ─────────────────────────────────────────────────────
function resolveLiveStatus(gw) {
  const now = nowUTC();

  if (gw.availability_type === "temporary") {
    if (!gw.temp_start || !gw.temp_end) {
      return {
        is_active: false,
        status:    "misconfigured",
        message:   "Temporary gateway is missing temp_start or temp_end",
      };
    }

    const start = new Date(gw.temp_start);
    const end   = new Date(gw.temp_end);

    if (now < start) {
      return {
        is_active:      false,
        status:         "scheduled",
        message:        `Scheduled to activate at ${start.toISOString()}`,
        activates_at:   start.toISOString(),
        deactivates_at: end.toISOString(),
      };
    }

    if (now > end) {
      return {
        is_active:      false,
        status:         "expired",
        message:        `Temporary window expired at ${end.toISOString()}`,
        deactivates_at: end.toISOString(),
      };
    }

    return {
      is_active:      true,
      status:         "active_temporary",
      message:        `Temporarily active until ${end.toISOString()}`,
      deactivates_at: end.toISOString(),
    };
  }

  if (gw.is_enabled) {
    return { is_active: true,  status: "active",   message: "Gateway is permanently active" };
  }
  return   { is_active: false, status: "disabled", message: gw.reason || "Gateway is disabled" };
}

// ─── Response Formatter ───────────────────────────────────────────────────────
function formatGateway(gw) {
  return {
    id:                gw.id,
    gateway_key:       gw.gateway_key,
    name:              gw.name,
    logo_url:          gw.logo_url,
    availability_type: gw.availability_type,
    is_enabled:        Boolean(gw.is_enabled),
    is_default:        Boolean(gw.is_default),
    display_order:     gw.display_order,
    temp_start:        toISO(gw.temp_start),
    temp_end:          toISO(gw.temp_end),
    reason:            gw.reason  || null,
    updated_by:        gw.updated_by,
    updated_at:        toISO(gw.updated_at),
    live_status:       resolveLiveStatus(gw),
  };
}

// ─── Manual Validation ────────────────────────────────────────────────────────
function validateCreate(data) {
  const { gateway_key, name, logo_url, availability_type, temp_start, temp_end } = data;

  if (!gateway_key || gateway_key.trim() === "") return "gateway_key is required";
  if (!name        || name.trim()        === "") return "name is required";
  if (!logo_url    || logo_url.trim()    === "") return "logo_url is required";
  if (!isValidURL(logo_url))                     return "logo_url must be a valid URL";

  if (availability_type && !["permanent", "temporary"].includes(availability_type)) {
    return "availability_type must be 'permanent' or 'temporary'";
  }

  if (availability_type === "temporary") {
    if (!temp_start)              return "temp_start is required for temporary availability";
    if (!temp_end)                return "temp_end is required for temporary availability";
    if (!isValidDate(temp_start)) return "temp_start must be a valid date";
    if (!isValidDate(temp_end))   return "temp_end must be a valid date";
    if (new Date(temp_end) <= new Date(temp_start)) return "temp_end must be after temp_start";
  }

  return null;
}

function validateUpdate(data, existing) {
  const { logo_url, availability_type, temp_start, temp_end } = data;

  if (logo_url !== undefined && !isValidURL(logo_url)) {
    return "logo_url must be a valid URL";
  }

  if (availability_type && !["permanent", "temporary"].includes(availability_type)) {
    return "availability_type must be 'permanent' or 'temporary'";
  }

  const mergedType  = availability_type  || existing.availability_type;
  const mergedStart = temp_start         || existing.temp_start;
  const mergedEnd   = temp_end           || existing.temp_end;

  if (mergedType === "temporary") {
    if (!mergedStart)                return "temp_start is required for temporary availability";
    if (!mergedEnd)                  return "temp_end is required for temporary availability";
    if (!isValidDate(mergedStart))   return "temp_start must be a valid date";
    if (!isValidDate(mergedEnd))     return "temp_end must be a valid date";
    if (new Date(mergedEnd) <= new Date(mergedStart)) return "temp_end must be after temp_start";
  }

  return null;
}

// ─── Service Methods ──────────────────────────────────────────────────────────

async function getAllGateways() {
  const rows = await GatewayModel.findAll();
  return rows.map(formatGateway);
}

async function getActiveGateways() {
  const rows = await GatewayModel.findAll();
  return rows.map(formatGateway).filter((g) => g.live_status.is_active);
}

async function getGatewayByKey(gateway_key) {
  const gw = await GatewayModel.findByKey(gateway_key);
  if (!gw) throw { status: 404, message: `Gateway '${gateway_key}' not found` };
  return formatGateway(gw);
}

async function createGateway(data) {
  const error = validateCreate(data);
  if (error) throw { status: 400, message: error };

  const existing = await GatewayModel.findByKey(data.gateway_key);
  if (existing)  throw { status: 409, message: `Gateway '${data.gateway_key}' already exists` };

  const created = await GatewayModel.create({
    ...data,
    is_enabled: data.is_enabled !== undefined ? (data.is_enabled ? 1 : 0) : 1,
    is_default: data.is_default !== undefined ? (data.is_default ? 1 : 0) : 0,
  });

  await GatewayModel.insertAudit(data.gateway_key, data.updated_by || "admin", "CREATED", null, created);
  return formatGateway(created);
}

async function updateGateway(gateway_key, data) {
  const old = await GatewayModel.findByKey(gateway_key);
  if (!old) throw { status: 404, message: `Gateway '${gateway_key}' not found` };

  const error = validateUpdate(data, old);
  if (error) throw { status: 400, message: error };

  const fields = [];
  const values = [];

  const map = {
    name:              (v) => v,
    logo_url:          (v) => v,
    availability_type: (v) => v,
    is_enabled:        (v) => (v ? 1 : 0),
    is_default:        (v) => (v ? 1 : 0),
    display_order:     (v) => v,
    temp_start:        (v) => v,
    temp_end:          (v) => v,
    reason:            (v) => v,
  };

  for (const [key, transform] of Object.entries(map)) {
    if (data[key] !== undefined) {
      fields.push(`${key} = ?`);
      values.push(transform(data[key]));
    }
  }

  fields.push("updated_by = ?");
  values.push(data.updated_by || "admin");

  if (data.availability_type === "permanent") {
    fields.push("temp_start = NULL", "temp_end = NULL");
  }

  if (fields.length <= 1) throw { status: 400, message: "No fields provided to update" };

  const updated = await GatewayModel.update(gateway_key, fields, values);
  await GatewayModel.insertAudit(gateway_key, data.updated_by || "admin", "UPDATED", old, updated);
  return formatGateway(updated);
}

async function toggleGateway(gateway_key, updated_by = "admin") {
  const gw = await GatewayModel.findByKey(gateway_key);
  if (!gw) throw { status: 404, message: `Gateway '${gateway_key}' not found` };

  if (gw.availability_type === "temporary") {
    throw { status: 400, message: "Toggle only works on permanent gateways. Use PATCH for temporary." };
  }

  const new_enabled = gw.is_enabled ? 0 : 1;
  const updated     = await GatewayModel.toggle(gateway_key, new_enabled, updated_by);
  await GatewayModel.insertAudit(gateway_key, updated_by, `TOGGLED → ${new_enabled ? "ENABLED" : "DISABLED"}`, gw, updated);
  return formatGateway(updated);
}

async function deleteGateway(gateway_key, updated_by = "admin") {
  const gw = await GatewayModel.findByKey(gateway_key);
  if (!gw) throw { status: 404, message: `Gateway '${gateway_key}' not found` };

  await GatewayModel.remove(gateway_key);
  await GatewayModel.insertAudit(gateway_key, updated_by, "DELETED", gw, null);
  return { message: `Gateway '${gateway_key}' deleted successfully` };
}

async function resetAllGateways(updated_by = "admin") {
  await GatewayModel.resetAll(updated_by);
  await GatewayModel.insertAudit("ALL", updated_by, "RESET ALL → permanent + enabled", null, null);
  return { message: "All gateways reset to permanently enabled" };
}

async function getAuditLog(gateway_key = null, limit = 50) {
  return GatewayModel.getAudit(gateway_key, Math.min(limit, 200));
}

module.exports = {
  getAllGateways,
  getActiveGateways,
  getGatewayByKey,
  createGateway,
  updateGateway,
  toggleGateway,
  deleteGateway,
  resetAllGateways,
  getAuditLog,
};
