const RUNTIME_STATE_KEY = "medtools.consultation.runtimeState";
const LONG_RECORDING_ALARM = "medtools.consultation.longRecording";
const STOPPED_FINISH_ALARM = "medtools.consultation.stoppedFinish";
bootBackgroundState();

chrome.action.onClicked.addListener(async (tab) => {
  const state = await refreshRecorderBadge();
  const overlayTab = await resolveOverlayTab(tab);
  if (state?.status === "recording" || state?.status === "stopped" || state?.status === "finish_pending") {
    await openOverlayOrNotify("recorder", overlayTab);
    return;
  }
  await openOverlayOrNotify("app", overlayTab);
});

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message?.type !== "MEDTOOLS_OPEN_APP_OVERLAY" && message?.type !== "MEDTOOLS_OPEN_RECORDER_OVERLAY") {
    return false;
  }

  openOverlayOrNotify(message.type === "MEDTOOLS_OPEN_RECORDER_OVERLAY" ? "recorder" : "app", sender?.tab || null)
    .then((result) => sendResponse(result))
    .catch((error) => {
      sendResponse({
        ok: false,
        message: error?.message || "Не вдалося показати віджет поверх вкладки."
      });
    });
  return true;
});

chrome.runtime.onInstalled.addListener(() => {
  refreshRecorderBadge().catch(() => {});
});
chrome.runtime.onStartup.addListener(() => {
  refreshRecorderBadge().catch(() => {});
});

chrome.storage.onChanged.addListener((changes, areaName) => {
  if (areaName !== "local" || !changes[RUNTIME_STATE_KEY]) {
    return;
  }
  updateRecorderBadge(changes[RUNTIME_STATE_KEY].newValue || null);
});

chrome.alarms.onAlarm.addListener((alarm) => {
  if (alarm.name === LONG_RECORDING_ALARM) {
    handleLongRecordingAlarm();
  } else if (alarm.name === STOPPED_FINISH_ALARM) {
    handleStoppedFinishAlarm();
  }
});

async function handleLongRecordingAlarm() {
  await refreshRecorderBadge().catch(() => {});
  const state = await getRuntimeState();
  if (state?.status !== "recording") {
    await chrome.alarms.clear(LONG_RECORDING_ALARM);
    return;
  }
  const minutes = elapsedMinutes(state.startedAt);
  showNotification(
    "Parallax Health",
    `Запис триває ${minutes} хв. Якщо консультація завершена, відкрийте запис і натисніть "Завершити".`
  );
}

async function handleStoppedFinishAlarm() {
  await refreshRecorderBadge().catch(() => {});
  const state = await getRuntimeState();
  if (state?.status !== "stopped" && state?.status !== "finish_pending") {
    await chrome.alarms.clear(STOPPED_FINISH_ALARM);
    return;
  }
  const message = state.status === "finish_pending"
    ? "Завершення ще не підтверджене сервером. Відкрийте запис і натисніть \"Перевірити\"."
    : "Запис зупинено, але консультацію ще не завершено. Відкрийте запис і натисніть \"Завершити\".";
  showNotification("Parallax Health", message);
}

async function bootBackgroundState() {
  await refreshRecorderBadge().catch(() => {});
}

async function getRuntimeState() {
  const values = await chrome.storage.local.get(RUNTIME_STATE_KEY);
  return values[RUNTIME_STATE_KEY] || null;
}

async function refreshRecorderBadge() {
  const state = await getRuntimeState();
  updateRecorderBadge(state);
  return state;
}

function updateRecorderBadge(state) {
  if (!chrome.action?.setBadgeText) {
    return;
  }
  const status = state?.status || "";
  if (status === "recording") {
    chrome.action.setBadgeText({ text: "REC" });
    chrome.action.setBadgeBackgroundColor({ color: "#dc2626" });
    chrome.action.setTitle({ title: runtimeBadgeTitle(state, "Запис триває") });
    return;
  }
  if (status === "stopped") {
    chrome.action.setBadgeText({ text: "STOP" });
    chrome.action.setBadgeBackgroundColor({ color: "#f59e0b" });
    chrome.action.setTitle({ title: runtimeBadgeTitle(state, "Запис зупинено, треба завершити") });
    return;
  }
  if (status === "finish_pending") {
    chrome.action.setBadgeText({ text: "..." });
    chrome.action.setBadgeBackgroundColor({ color: "#2563eb" });
    chrome.action.setTitle({ title: runtimeBadgeTitle(state, "Досилається завершення") });
    return;
  }
  chrome.action.setBadgeText({ text: "" });
  chrome.action.setTitle({ title: "Parallax Health" });
}

function runtimeBadgeTitle(state, label) {
  const parts = [`Parallax Health: ${label}`];
  if (state?.startedAt) {
    parts.push(`${elapsedMinutes(state.startedAt)} хв`);
  }
  if (Number.isFinite(Number(state?.chunkCount))) {
    parts.push(`${Number(state.chunkCount)} чанків`);
  }
  if (Number.isFinite(Number(state?.pendingCount)) && Number(state.pendingCount) > 0) {
    parts.push(`черга ${Number(state.pendingCount)}`);
  }
  return parts.join(" · ");
}

function elapsedMinutes(startedAt) {
  const startedMs = Date.parse(startedAt || "");
  if (!startedMs) {
    return 45;
  }
  return Math.max(1, Math.round((Date.now() - startedMs) / 60000));
}

function showNotification(title, message) {
  chrome.notifications.create(`medtools-${Date.now()}`, {
    type: "basic",
    iconUrl: "assets/icons/icon-128.png",
    title,
    message,
    priority: 1
  });
}

async function showRecorderOverlayInCurrentTab(activeTab) {
  return showOverlayInCurrentTab(activeTab, "MEDTOOLS_SHOW_RECORDER_OVERLAY", { compact: false });
}

async function showAppOverlayInCurrentTab(activeTab) {
  return showOverlayInCurrentTab(activeTab, "MEDTOOLS_SHOW_APP_OVERLAY", {});
}

async function openOverlayOrNotify(kind, preferredTab) {
  const overlayTab = await resolveOverlayTab(preferredTab);
  const shown = kind === "recorder"
    ? await showRecorderOverlayInCurrentTab(overlayTab)
    : await showAppOverlayInCurrentTab(overlayTab);
  if (shown) {
    return { ok: true, shown: true };
  }

  const message = "Віджет не вдалося показати поверх відкритої сторінки. Відкрийте Лакмус або звичайну https-сторінку і натисніть Parallax Health ще раз.";
  showNotification("Parallax Health", message);
  return { ok: false, shown: false, message };
}

async function showOverlayInCurrentTab(activeTab, messageType, options) {
  try {
    const targetTab = activeTab?.id ? activeTab : await currentActiveTab();
    if (!targetTab?.id) {
      return false;
    }
    if (!canInjectIntoTab(targetTab)) {
      return false;
    }
    await sendOverlayMessage(targetTab.id, messageType, options);
    if (targetTab.windowId) {
      await chrome.windows.update(targetTab.windowId, { focused: true });
    }
    await chrome.tabs.update(targetTab.id, { active: true });
    return true;
  } catch (error) {
    return false;
  }
}

async function currentActiveTab() {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  return tab || null;
}

async function resolveOverlayTab(activeTab) {
  const targetTab = activeTab?.id ? activeTab : await currentActiveTab();
  if (targetTab?.id && canInjectIntoTab(targetTab)) {
    return targetTab;
  }

  const lakmusTab = await findLakmusTab();
  if (lakmusTab) {
    return lakmusTab;
  }

  const injectableTab = await findInjectableTab();
  if (injectableTab) {
    return injectableTab;
  }

  return targetTab || null;
}

async function findLakmusTab() {
  const tabs = await chrome.tabs.query({ url: "https://baddi.lakmus.org/*" });
  if (!tabs.length) {
    return null;
  }
  return (
    tabs.find((tab) => tab.active && tab.currentWindow) ||
    tabs.find((tab) => tab.active) ||
    tabs[0]
  );
}

async function findInjectableTab() {
  const currentWindowTabs = await chrome.tabs.query({ currentWindow: true });
  const currentWindowCandidate = currentWindowTabs.find((tab) => tab.id && canInjectIntoTab(tab));
  if (currentWindowCandidate) {
    return currentWindowCandidate;
  }

  const tabs = await chrome.tabs.query({});
  return tabs.find((tab) => tab.id && canInjectIntoTab(tab)) || null;
}

function canInjectIntoTab(tab) {
  return /^https?:\/\//.test(tab.url || "");
}

async function sendOverlayMessage(tabId, messageType, options) {
  try {
    return await chrome.tabs.sendMessage(tabId, {
      type: messageType,
      options
    });
  } catch (error) {
    if (!chrome.scripting?.executeScript) {
      throw error;
    }
    await chrome.scripting.executeScript({
      target: { tabId },
      files: ["lakmus-content.js"]
    });
    return chrome.tabs.sendMessage(tabId, {
      type: messageType,
      options
    });
  }
}
