const ADMIN_TOKEN_KEY = "admin_token";
const ADMIN_PROFILE_KEY = "admin_profile";

function resolveAdminApiBase() {
  const host = window.location.hostname;
  const port = window.location.port;
  const configured = window.SOUNDBOX_ADMIN_API_BASE || "";
  if (configured) {
    return configured.replace(/\/$/, "");
  }
  if ((host === "127.0.0.1" || host === "localhost") && port === "4173") {
    return "http://127.0.0.1:3100";
  }
  return "";
}

const ADMIN_API_BASE = resolveAdminApiBase();

function formatMoney(value) {
  const number = Number(value || 0);
  if (!Number.isFinite(number)) {
    return "Rp 0";
  }
  return new Intl.NumberFormat("id-ID", {
    style: "currency",
    currency: "IDR",
    maximumFractionDigits: 0
  }).format(number);
}

function formatDateTime(value) {
  if (!value) {
    return "-";
  }

  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    return value;
  }

  return new Intl.DateTimeFormat("en-GB", {
    dateStyle: "medium",
    timeStyle: "short"
  }).format(date);
}

function buildQuery(query) {
  const search = new URLSearchParams();
  Object.entries(query || {}).forEach(([key, val]) => {
    if (val !== undefined && val !== null && val !== "") {
      search.append(key, String(val));
    }
  });
  return search.toString();
}

async function adminFetch(path, options = {}) {
  const token = localStorage.getItem(ADMIN_TOKEN_KEY);
  const {
    method = "GET",
    query,
    body,
    headers: extraHeaders = {},
    auth = true
  } = options;

  const suffix = buildQuery(query || {});
  const relativeUrl = suffix ? `${path}?${suffix}` : path;
  const url = `${ADMIN_API_BASE}${relativeUrl}`;
  const headers = {
    ...extraHeaders
  };

  if (auth) {
    if (!token) {
      throw new Error("ADMIN_AUTH_MISSING");
    }
    headers.Authorization = `Bearer ${token}`;
  }

  if (method !== "GET" && body !== undefined) {
    headers["Content-Type"] = "application/json";
  }

  const response = await fetch(url, {
    method,
    headers,
    body: method === "GET" || body === undefined ? undefined : JSON.stringify(body)
  });

  const raw = await response.text();
  let payload;
  try {
    payload = raw ? JSON.parse(raw) : {};
  } catch (error) {
    payload = {};
  }

  if (!response.ok) {
    const message =
      payload?.message ||
      payload?.error ||
      `Request failed with status ${response.status}`;
    throw new Error(message);
  }

  return payload?.data !== undefined ? payload.data : payload;
}

function hasPermission(profile, permission) {
  if (!permission) {
    return true;
  }
  const permissions = profile?.permissions;
  if (!permissions) {
    return false;
  }
  if (Array.isArray(permissions)) {
    return permissions.includes("*") || permissions.includes(permission);
  }
  if (permissions.admin === "*" || permissions.admin === true) {
    return true;
  }
  if (permissions[permission] === "*" || permissions[permission] === true) {
    return true;
  }
  const [domain, action] = permission.split(":");
  const domainValue = permissions[domain];
  if (domainValue === "*" || domainValue === true) {
    return true;
  }
  if (Array.isArray(domainValue)) {
    return domainValue.includes("*") || domainValue.includes(action);
  }
  if (domainValue && typeof domainValue === "object") {
    return domainValue[action] === "*" || domainValue[action] === true;
  }
  return false;
}

function getStoredProfile() {
  try {
    return JSON.parse(localStorage.getItem(ADMIN_PROFILE_KEY) || "null");
  } catch (_error) {
    return null;
  }
}

function applyPermissionAttributes(profile) {
  document.querySelectorAll("[data-admin-permission]").forEach((el) => {
    const allowed = hasPermission(profile, el.getAttribute("data-admin-permission"));
    el.classList.toggle("hidden", !allowed);
    if ("disabled" in el) {
      el.disabled = !allowed;
    }
  });
}

window.AdminUIAPI = {
  ADMIN_TOKEN_KEY,
  ADMIN_PROFILE_KEY,
  setToken: (token) => localStorage.setItem(ADMIN_TOKEN_KEY, token),
  getToken: () => localStorage.getItem(ADMIN_TOKEN_KEY),
  clearToken: () => {
    localStorage.removeItem(ADMIN_TOKEN_KEY);
    localStorage.removeItem(ADMIN_PROFILE_KEY);
  },
  requireToken: () => {
    const token = localStorage.getItem(ADMIN_TOKEN_KEY);
    if (!token) {
      window.location.href = "/ui/admin-login";
      throw new Error("ADMIN_AUTH_MISSING");
    }
    return token;
  },
  login: async ({ username, password }) => {
    const data = await adminFetch("/admin/login", {
      method: "POST",
      auth: false,
      body: { username, password }
    });
    if (data?.token) {
      window.AdminUIAPI.setToken(data.token);
      if (data.user) {
        localStorage.setItem(ADMIN_PROFILE_KEY, JSON.stringify(data.user));
      }
    }
    return data;
  },
  getMe: async () => {
    const profile = await adminFetch("/admin/me");
    localStorage.setItem(ADMIN_PROFILE_KEY, JSON.stringify(profile));
    return profile;
  },
  getStoredProfile,
  hasPermission: (permission, profile) => hasPermission(profile || getStoredProfile(), permission),
  applyPermissions: async () => {
    let profile = getStoredProfile();
    if (!profile?.permissions) {
      profile = await window.AdminUIAPI.getMe();
    }
    applyPermissionAttributes(profile);
    return profile;
  },
  listMerchants: () => adminFetch("/admin/merchants"),
  listOutlets: (query) => adminFetch("/admin/outlets", { query }),
  getOutlet: (id) => adminFetch(`/admin/outlets/${id}`),
  getMerchant: (id) => adminFetch(`/admin/merchants/${id}`),
  patchMerchant: (id, payload) =>
    adminFetch(`/admin/merchants/${id}`, {
      method: "PATCH",
      body: payload
    }),
  approveMerchant: (id) => adminFetch(`/admin/merchants/${id}/approve`, { method: "POST" }),
  rejectMerchant: (id, payload) =>
    adminFetch(`/admin/merchants/${id}/reject`, {
      method: "POST",
      body: payload || {}
    }),
  listTerminals: (query) => adminFetch("/admin/terminals", { query }),
  getTerminal: (id) => adminFetch(`/admin/terminals/${id}`),
  listSoundboxVendors: (query) => adminFetch("/admin/soundbox-vendors", { query }),
  createSoundboxVendor: (payload) =>
    adminFetch("/admin/soundbox-vendors", {
      method: "POST",
      body: payload || {}
    }),
  patchSoundboxVendor: (id, payload) =>
    adminFetch(`/admin/soundbox-vendors/${id}`, {
      method: "PATCH",
      body: payload || {}
    }),
  deleteSoundboxVendor: (id) =>
    adminFetch(`/admin/soundbox-vendors/${id}`, {
      method: "DELETE"
    }),
  listSoundboxModels: (query) => adminFetch("/admin/soundbox-models", { query }),
  createSoundboxModel: (payload) =>
    adminFetch("/admin/soundbox-models", {
      method: "POST",
      body: payload || {}
    }),
  patchSoundboxModel: (id, payload) =>
    adminFetch(`/admin/soundbox-models/${id}`, {
      method: "PATCH",
      body: payload || {}
    }),
  deleteSoundboxModel: (id) =>
    adminFetch(`/admin/soundbox-models/${id}`, {
      method: "DELETE"
    }),
  listDevices: (query) => adminFetch("/admin/devices", { query }),
  createDevice: (payload) =>
    adminFetch("/admin/devices", {
      method: "POST",
      body: payload || {}
    }),
  getDevice: (id) => adminFetch(`/admin/devices/${id}`),
  patchDevice: (id, payload) =>
    adminFetch(`/admin/devices/${id}`, {
      method: "PATCH",
      body: payload || {}
    }),
  bindDevice: (id, payload) =>
    adminFetch(`/admin/devices/${id}/bind`, {
      method: "POST",
      body: payload || {}
    }),
  unbindDevice: (id) =>
    adminFetch(`/admin/devices/${id}/unbind`, {
      method: "POST",
      body: {}
    }),
  createDeviceCommand: (id, payload) =>
    adminFetch(`/admin/devices/${id}/commands`, {
      method: "POST",
      body: payload || {}
    }),
  listDeviceCommands: (id, query) =>
    adminFetch(`/admin/devices/${id}/commands`, { query }),
  rotateDeviceCredential: (id) =>
    adminFetch(`/admin/devices/${id}/credentials/rotate`, {
      method: "POST",
      body: {}
    }),
  getDeviceHeartbeats: (id, query) =>
    adminFetch(`/admin/devices/${id}/heartbeats`, { query }),
  getDeviceConfig: (id) => adminFetch(`/admin/devices/${id}/config`),
  getDeviceConfigStatus: (id) => adminFetch(`/admin/devices/${id}/config/status`),
  retryDeviceConfigPush: (id, payload) =>
    adminFetch(`/admin/devices/${id}/config/retry-push`, {
      method: "POST",
      body: payload || {}
    }),
  listTransactions: (query) => adminFetch("/admin/transactions", { query }),
  getDynamicQrExpiryScheduler: () => adminFetch("/admin/transactions/expiry-scheduler"),
  createSettlementBatches: (payload) =>
    adminFetch("/admin/settlement-batches", {
      method: "POST",
      body: payload || {}
    }),
  listSettlementBatches: (query) => adminFetch("/admin/settlement-batches", { query }),
  getSettlementBatch: (id) => adminFetch(`/admin/settlement-batches/${id}`),
  listSettlementAdjustments: (query) =>
    adminFetch("/admin/settlement-adjustments", { query }),
  createSettlementAdjustmentExportJob: (payload) =>
    adminFetch("/admin/exports/settlement-adjustments", {
      method: "POST",
      body: payload || {}
    }),
  getExportJob: (id) => adminFetch(`/admin/exports/${id}`),
  listExportJobs: (query) => adminFetch("/admin/exports", { query }),
  downloadExportJob: async (id) => {
    const token = localStorage.getItem(ADMIN_TOKEN_KEY);
    if (!token) {
      throw new Error("ADMIN_AUTH_MISSING");
    }
    const response = await fetch(`/admin/exports/${id}/download`, {
      headers: { Authorization: `Bearer ${token}` }
    });
    if (!response.ok) {
      throw new Error(`Export download failed: ${response.status}`);
    }
    return {
      blob: await response.blob(),
      filename:
        response.headers.get("content-disposition")?.match(/filename="([^"]+)"/)?.[1] ||
        `${id}.csv`
    };
  },
  getSettlementReconciliationReport: (query) =>
    adminFetch("/admin/reconciliation/settlement-batches", { query }),
  markSettlementBatchPaid: (id, payload) =>
    adminFetch(`/admin/settlement-batches/${id}/mark-paid`, {
      method: "POST",
      body: payload || {}
    }),
  updateSettlementBatchReference: (id, payload) =>
    adminFetch(`/admin/settlement-batches/${id}/reference`, {
      method: "PATCH",
      body: payload || {}
    }),
  recordSettlementBatchAdjustment: (id, payload) =>
    adminFetch(`/admin/settlement-batches/${id}/adjustments`, {
      method: "POST",
      body: payload || {}
    }),
  approveSettlementAdjustment: (id, payload) =>
    adminFetch(`/admin/settlement-adjustments/${id}/approve`, {
      method: "POST",
      body: payload || {}
    }),
  rejectSettlementAdjustment: (id, payload) =>
    adminFetch(`/admin/settlement-adjustments/${id}/reject`, {
      method: "POST",
      body: payload || {}
    }),
  markSettlementBatchFailed: (id, payload) =>
    adminFetch(`/admin/settlement-batches/${id}/mark-failed`, {
      method: "POST",
      body: payload || {}
    }),
  cancelSettlementBatch: (id, payload) =>
    adminFetch(`/admin/settlement-batches/${id}/cancel`, {
      method: "POST",
      body: payload || {}
    }),
  reprocessSettlementBatch: (id) =>
    adminFetch(`/admin/settlement-batches/${id}/reprocess`, {
      method: "POST",
      body: {}
    }),
  getDashboardSummary: () => adminFetch("/admin/dashboard/summary"),
  getMqttStatus: (query) => adminFetch("/admin/mqtt/status", { query }),
  getObservabilitySummary: () => adminFetch("/admin/observability/summary"),
  listFailedNotifications: (query) => adminFetch("/admin/notifications/failed", { query }),
  listAuditLogs: (query) => adminFetch("/admin/audit-logs", { query }),
  formatMoney,
  formatDateTime
};
