/**
 * Theme accent (primary color) + page background preferences.
 * Accent and page background are independent; wallpaper is local-only.
 */
const DEFAULT_ACCENT = {
  primary: '#4A9FE8',
  rgb: '74, 159, 232',
  light: '#7BB8F0'
};

const CUSTOM_BG_CLASS = 'custom-theme-background';

const BACKGROUND_ACCENTS = {
  'gradient-background-1': {
    primary: '#4A8FD4',
    rgb: '74, 143, 212',
    light: '#7AAFE6'
  },
  'gradient-background-2': {
    primary: '#2B9AE8',
    rgb: '43, 154, 232',
    light: '#6BB8F0'
  },
  'gradient-background-3': {
    primary: '#6B7FE8',
    rgb: '107, 127, 232',
    light: '#95A4F2'
  },
  'gradient-background-4': {
    primary: '#2A9FB0',
    rgb: '42, 159, 176',
    light: '#5BC0CE'
  },
  'gradient-background-5': {
    primary: '#3AADD8',
    rgb: '58, 173, 216',
    light: '#6FC6E6'
  },
  'gradient-background-6': {
    primary: '#5A7FC0',
    rgb: '90, 127, 192',
    light: '#87A4D4'
  },
  'gradient-background-7': DEFAULT_ACCENT
};

function normalizeHex(hex) {
  if (!hex || typeof hex !== 'string') return null;
  let value = hex.trim();
  if (!value.startsWith('#')) value = `#${value}`;
  if (/^#[0-9a-fA-F]{3}$/.test(value)) {
    value = `#${value[1]}${value[1]}${value[2]}${value[2]}${value[3]}${value[3]}`;
  }
  if (!/^#[0-9a-fA-F]{6}$/.test(value)) return null;
  return value.toUpperCase();
}

function hexToRgb(hex) {
  const normalized = normalizeHex(hex);
  if (!normalized) return null;
  return {
    r: parseInt(normalized.slice(1, 3), 16),
    g: parseInt(normalized.slice(3, 5), 16),
    b: parseInt(normalized.slice(5, 7), 16)
  };
}

function mixWithWhite(hex, amount = 0.88) {
  const rgb = hexToRgb(hex);
  if (!rgb) return '#F0F6FC';
  const mix = (c) => Math.round(c + (255 - c) * amount);
  return `rgb(${mix(rgb.r)}, ${mix(rgb.g)}, ${mix(rgb.b)})`;
}

function lightenHex(hex, amount = 0.35) {
  const rgb = hexToRgb(hex);
  if (!rgb) return DEFAULT_ACCENT.light;
  const mix = (c) => Math.round(c + (255 - c) * amount);
  const toHex = (n) => n.toString(16).padStart(2, '0');
  return `#${toHex(mix(rgb.r))}${toHex(mix(rgb.g))}${toHex(mix(rgb.b))}`.toUpperCase();
}

function accentFromHex(hex) {
  const normalized = normalizeHex(hex) || DEFAULT_ACCENT.primary;
  const rgb = hexToRgb(normalized);
  return {
    primary: normalized,
    rgb: rgb ? `${rgb.r}, ${rgb.g}, ${rgb.b}` : DEFAULT_ACCENT.rgb,
    light: lightenHex(normalized, 0.35)
  };
}

function setAccentCssVars(accent) {
  const root = document.documentElement;
  root.style.setProperty('--primary-color', accent.primary);
  root.style.setProperty('--primary-color-rgb', accent.rgb);
  root.style.setProperty('--primary-color-light', accent.light);
}

function clearCustomThemeBackgroundClass() {
  const root = document.documentElement;
  root.classList.remove(CUSTOM_BG_CLASS);
  root.style.removeProperty('--theme-page-bg');
}

function preserveRootMeta(mutator) {
  const root = document.documentElement;
  const theme = root.getAttribute('data-theme');
  mutator(root);
  if (theme) root.setAttribute('data-theme', theme);
}

function applyCustomThemeBackground(hex) {
  const normalized = normalizeHex(hex) || DEFAULT_ACCENT.primary;
  preserveRootMeta((root) => {
    const classes = Array.from(root.classList).filter(
      (c) => !c.startsWith('gradient-background') && c !== CUSTOM_BG_CLASS && c !== 'loading-wallpaper'
    );
    root.className = classes.join(' ');
    root.classList.add(CUSTOM_BG_CLASS);
    root.style.setProperty('--theme-page-bg', mixWithWhite(normalized, 0.88));
  });
}

function applyGradientPageBackground(bgClass) {
  if (!bgClass || bgClass === CUSTOM_BG_CLASS) return;
  preserveRootMeta((root) => {
    root.style.removeProperty('--theme-page-bg');
    const keep = Array.from(root.classList).filter(
      (c) => !c.startsWith('gradient-background') && c !== CUSTOM_BG_CLASS && c !== 'loading-wallpaper'
    );
    root.className = keep.concat(bgClass).join(' ');
  });
}

function resolveAccent(bgClass) {
  return BACKGROUND_ACCENTS[bgClass] || DEFAULT_ACCENT;
}

function persistThemePreference(partial) {
  const localPayload = {};
  try {
    Object.entries(partial).forEach(([key, value]) => {
      if (value == null) {
        localStorage.removeItem(key);
      } else {
        localStorage.setItem(key, String(value));
        localPayload[key] = value;
      }
    });
  } catch (_) {
    /* ignore quota / private mode */
  }

  try {
    if (typeof chrome !== 'undefined' && chrome.storage?.local) {
      const toSet = {};
      const toRemove = [];
      Object.entries(partial).forEach(([key, value]) => {
        if (value == null) toRemove.push(key);
        else toSet[key] = value;
      });
      if (Object.keys(toSet).length) chrome.storage.local.set(toSet);
      if (toRemove.length) chrome.storage.local.remove(toRemove);
    }
  } catch (_) {
    /* ignore */
  }

  try {
    if (window.TabMarkDataSync?.setSyncedData) {
      window.TabMarkDataSync.setSyncedData(partial);
    }
  } catch (_) {
    /* ignore */
  }
}

function syncCustomAccentPicker(hex) {
  const picker = document.getElementById('custom-theme-color-picker');
  const normalized = normalizeHex(hex) || DEFAULT_ACCENT.primary;
  if (picker) picker.value = normalized;

  const option = document.querySelector('.settings-custom-accent-option');
  if (!option) return;
  option.style.setProperty('--custom-swatch-color', normalized);
  option.classList.toggle('active', localStorage.getItem('themeAccentMode') === 'custom');
}

function syncCustomBackgroundPicker(hex) {
  const picker = document.getElementById('custom-background-color-picker');
  const normalized = normalizeHex(hex) || DEFAULT_ACCENT.primary;
  if (picker) picker.value = normalized;

  const option = document.querySelector('.settings-custom-bg-option');
  if (!option) return;
  option.style.setProperty('--custom-swatch-color', normalized);
  const isCustomBg =
    localStorage.getItem('useDefaultBackground') === 'true' &&
    localStorage.getItem('selectedBackground') === CUSTOM_BG_CLASS;
  option.classList.toggle('active', isCustomBg);
}

function updateAccentActiveState(accentKey) {
  document.querySelectorAll('.settings-accent-option').forEach((opt) => {
    opt.classList.toggle('active', !!accentKey && opt.getAttribute('data-accent') === accentKey);
  });
  const customOption = document.querySelector('.settings-custom-accent-option');
  if (customOption) {
    customOption.classList.toggle('active', localStorage.getItem('themeAccentMode') === 'custom');
  }
}

function updateBackgroundActiveState(bgClass) {
  document.querySelectorAll('.settings-bg-option').forEach((opt) => {
    opt.classList.toggle(
      'active',
      !!bgClass &&
        bgClass !== CUSTOM_BG_CLASS &&
        opt.getAttribute('data-bg') === bgClass &&
        localStorage.getItem('useDefaultBackground') === 'true'
    );
  });
  syncCustomBackgroundPicker(
    localStorage.getItem('customBackgroundColor') ||
      localStorage.getItem('customThemeColor') ||
      DEFAULT_ACCENT.primary
  );
}

/** Accent only — does not change page background or wallpaper. */
function applyThemeAccent(accentKey, { persist = true } = {}) {
  const key = accentKey || localStorage.getItem('themeAccentBackground') || 'gradient-background-7';
  const accent = resolveAccent(key);
  setAccentCssVars(accent);

  if (persist) {
    persistThemePreference({
      themeAccentMode: 'preset',
      themeAccentBackground: key
    });
  } else {
    localStorage.setItem('themeAccentMode', 'preset');
    localStorage.setItem('themeAccentBackground', key);
  }

  const custom = localStorage.getItem('customThemeColor');
  syncCustomAccentPicker(custom || accent.primary);
  updateAccentActiveState(key);
  return accent;
}

/** Custom accent only — does not force page background unless applyBackground is true. */
function applyCustomThemeAccent(hex, { applyBackground = false, persist = true } = {}) {
  const normalized = normalizeHex(hex) || DEFAULT_ACCENT.primary;
  const accent = accentFromHex(normalized);
  setAccentCssVars(accent);

  if (persist) {
    const payload = {
      customThemeColor: normalized,
      themeAccentMode: 'custom',
      themeAccentBackground: CUSTOM_BG_CLASS
    };
    if (applyBackground) {
      payload.useDefaultBackground = true;
      payload.selectedBackground = CUSTOM_BG_CLASS;
      payload.customBackgroundColor = normalized;
    }
    persistThemePreference(payload);
  } else {
    localStorage.setItem('themeAccentMode', 'custom');
    localStorage.setItem('customThemeColor', normalized);
    localStorage.setItem('themeAccentBackground', CUSTOM_BG_CLASS);
  }

  if (applyBackground) {
    applyCustomThemeBackground(normalized);
    updateBackgroundActiveState(CUSTOM_BG_CLASS);
  }

  syncCustomAccentPicker(normalized);
  updateAccentActiveState(null);
  document.querySelector('.settings-custom-accent-option')?.classList.add('active');
  return accent;
}

function clearWallpaperDom() {
  document.body.classList.remove('has-wallpaper');
  document.body.style.removeProperty('--wallpaper-image');
  document.body.style.backgroundImage = 'none';
  const mainElement = document.querySelector('main');
  if (mainElement) mainElement.style.backgroundImage = 'none';
  try {
    localStorage.removeItem('originalWallpaper');
  } catch (_) {
    /* ignore */
  }
  document.querySelectorAll('.wallpaper-option, .bing-wallpaper-item').forEach((opt) => {
    opt.classList.remove('active');
  });
}

/** Page background only — does not change accent. Clears wallpaper. */
function applyPageBackground(bgClass, { persist = true, clearWallpaper = true } = {}) {
  if (!bgClass) return;

  if (clearWallpaper) clearWallpaperDom();

  if (bgClass === CUSTOM_BG_CLASS) {
    const hex =
      localStorage.getItem('customBackgroundColor') ||
      localStorage.getItem('customThemeColor') ||
      DEFAULT_ACCENT.primary;
    applyCustomThemeBackground(hex);
  } else {
    applyGradientPageBackground(bgClass);
  }

  if (persist) {
    persistThemePreference({
      selectedBackground: bgClass,
      useDefaultBackground: true
    });
  } else {
    localStorage.setItem('selectedBackground', bgClass);
    localStorage.setItem('useDefaultBackground', 'true');
  }

  updateBackgroundActiveState(bgClass);
}

/** Custom page background only — does not change accent. Clears wallpaper. */
function applyCustomPageBackground(hex, { persist = true, clearWallpaper = true } = {}) {
  const normalized = normalizeHex(hex) || DEFAULT_ACCENT.primary;
  if (clearWallpaper) clearWallpaperDom();
  applyCustomThemeBackground(normalized);

  if (persist) {
    persistThemePreference({
      selectedBackground: CUSTOM_BG_CLASS,
      useDefaultBackground: true,
      customBackgroundColor: normalized
    });
  } else {
    localStorage.setItem('selectedBackground', CUSTOM_BG_CLASS);
    localStorage.setItem('useDefaultBackground', 'true');
    localStorage.setItem('customBackgroundColor', normalized);
  }

  updateBackgroundActiveState(CUSTOM_BG_CLASS);
  syncCustomBackgroundPicker(normalized);
  return normalized;
}

/** Mark wallpaper mode in all storages so chrome.storage cannot revive solid bg. */
function markWallpaperBackgroundMode() {
  clearCustomThemeBackgroundClass();
  preserveRootMeta((root) => {
    const keep = Array.from(root.classList).filter(
      (c) => !c.startsWith('gradient-background') && c !== CUSTOM_BG_CLASS && c !== 'loading-wallpaper'
    );
    root.className = keep.join(' ');
  });
  persistThemePreference({ useDefaultBackground: false });
  updateBackgroundActiveState(null);
}

function applyThemeAccentFromStorage() {
  const mode = localStorage.getItem('themeAccentMode');
  const custom = localStorage.getItem('customThemeColor');
  const accentKey = localStorage.getItem('themeAccentBackground');
  const savedBg = localStorage.getItem('selectedBackground');

  if (mode === 'custom' && custom) {
    return applyCustomThemeAccent(custom, { applyBackground: false, persist: false });
  }

  // Migrate older installs where accent was tied to selectedBackground
  const key =
    accentKey && accentKey !== CUSTOM_BG_CLASS
      ? accentKey
      : savedBg && savedBg !== CUSTOM_BG_CLASS
        ? savedBg
        : 'gradient-background-7';
  const accent = applyThemeAccent(key, { persist: false });
  syncCustomAccentPicker(custom || accent.primary);
  return accent;
}

function applyPageBackgroundFromStorage() {
  const hasWallpaper = !!localStorage.getItem('originalWallpaper');
  const useDefault = localStorage.getItem('useDefaultBackground') === 'true';

  if (hasWallpaper && !useDefault) {
    updateBackgroundActiveState(null);
    return null;
  }

  if (!useDefault && hasWallpaper) {
    updateBackgroundActiveState(null);
    return null;
  }

  if (!useDefault) {
    updateBackgroundActiveState(null);
    return null;
  }

  const savedBg = localStorage.getItem('selectedBackground') || 'gradient-background-7';
  if (savedBg === CUSTOM_BG_CLASS) {
    const hex =
      localStorage.getItem('customBackgroundColor') ||
      localStorage.getItem('customThemeColor') ||
      DEFAULT_ACCENT.primary;
    applyCustomPageBackground(hex, { persist: false, clearWallpaper: false });
    return CUSTOM_BG_CLASS;
  }

  applyPageBackground(savedBg, { persist: false, clearWallpaper: false });
  return savedBg;
}

function writeStorageFlagToLocal(key, value) {
  if (value == null) return;
  if (value === true || value === 'true') localStorage.setItem(key, 'true');
  else if (value === false || value === 'false') localStorage.setItem(key, 'false');
  else localStorage.setItem(key, String(value));
}

function restoreThemeAccentFromChromeStorage() {
  return new Promise((resolve) => {
    if (typeof chrome === 'undefined' || !chrome.storage?.local) {
      applyThemeAccentFromStorage();
      applyPageBackgroundFromStorage();
      resolve();
      return;
    }

    const keys = [
      'customThemeColor',
      'customBackgroundColor',
      'themeAccentMode',
      'themeAccentBackground',
      'selectedBackground',
      'useDefaultBackground'
    ];

    chrome.storage.local.get(keys, (localResult) => {
      const applyChromeResult = (result) => {
        if (!result) return;
        if (result.customThemeColor) localStorage.setItem('customThemeColor', result.customThemeColor);
        if (result.customBackgroundColor) {
          localStorage.setItem('customBackgroundColor', result.customBackgroundColor);
        }
        if (result.themeAccentMode) localStorage.setItem('themeAccentMode', result.themeAccentMode);
        if (result.themeAccentBackground) {
          localStorage.setItem('themeAccentBackground', result.themeAccentBackground);
        }
        if (result.selectedBackground) {
          localStorage.setItem('selectedBackground', result.selectedBackground);
        }
        // Never revive solid background over a saved wallpaper unless chrome says true
        // and there is no wallpaper — if wallpaper exists and chrome says false, keep false.
        if (result.useDefaultBackground != null) {
          const hasWallpaper = !!localStorage.getItem('originalWallpaper');
          if (hasWallpaper && (result.useDefaultBackground === false || result.useDefaultBackground === 'false')) {
            writeStorageFlagToLocal('useDefaultBackground', false);
          } else if (hasWallpaper && (result.useDefaultBackground === true || result.useDefaultBackground === 'true')) {
            // Stale solid flag while wallpaper exists: prefer wallpaper
            writeStorageFlagToLocal('useDefaultBackground', false);
          } else {
            writeStorageFlagToLocal('useDefaultBackground', result.useDefaultBackground);
          }
        }
      };

      applyChromeResult(localResult);

      chrome.storage.sync.get(keys, (syncResult) => {
        if (!chrome.runtime.lastError && syncResult) {
          applyChromeResult(syncResult);
        }
        applyThemeAccentFromStorage();
        applyPageBackgroundFromStorage();
        resolve();
      });
    });
  });
}

function getCustomThemeColor() {
  return normalizeHex(localStorage.getItem('customThemeColor')) || DEFAULT_ACCENT.primary;
}

function getCustomBackgroundColor() {
  return (
    normalizeHex(localStorage.getItem('customBackgroundColor')) ||
    normalizeHex(localStorage.getItem('customThemeColor')) ||
    DEFAULT_ACCENT.primary
  );
}

function isCustomThemeAccentActive() {
  return localStorage.getItem('themeAccentMode') === 'custom';
}

const DEFAULT_GLASS_OPACITY = 48;
const MIN_GLASS_OPACITY = 20;
const MAX_GLASS_OPACITY = 100;

function clampGlassOpacityPercent(value) {
  const n = Number(value);
  if (!Number.isFinite(n)) return DEFAULT_GLASS_OPACITY;
  return Math.min(MAX_GLASS_OPACITY, Math.max(MIN_GLASS_OPACITY, Math.round(n)));
}

function applyGlassOpacity(percent, { persist = false } = {}) {
  const p = clampGlassOpacityPercent(percent);
  const opacity = p / 100;
  const soft = Math.max(0.12, Math.round(opacity * (0.35 / 0.48) * 1000) / 1000);
  const card = Math.max(0.15, Math.round(opacity * (0.42 / 0.48) * 1000) / 1000);
  const elevated = Math.min(0.98, Math.round((opacity + (1 - opacity) * 0.88) * 1000) / 1000);

  const root = document.documentElement;
  root.style.setProperty('--glass-opacity', String(opacity));
  root.style.setProperty('--glass-opacity-soft', String(soft));
  root.style.setProperty('--glass-opacity-card', String(card));
  root.style.setProperty('--glass-opacity-elevated', String(elevated));

  if (persist) {
    persistThemePreference({ glassOpacity: p });
  } else {
    try {
      localStorage.setItem('glassOpacity', String(p));
    } catch (_) {
      /* ignore */
    }
  }

  return p;
}

function applyGlassOpacityFromStorage() {
  const saved = localStorage.getItem('glassOpacity');
  return applyGlassOpacity(saved != null ? saved : DEFAULT_GLASS_OPACITY, { persist: false });
}

function restoreGlassOpacityFromChromeStorage() {
  return new Promise((resolve) => {
    if (typeof chrome === 'undefined' || !chrome.storage?.local) {
      resolve(applyGlassOpacityFromStorage());
      return;
    }

    chrome.storage.local.get(['glassOpacity'], (localResult) => {
      if (localResult.glassOpacity != null) {
        localStorage.setItem('glassOpacity', String(localResult.glassOpacity));
      }

      chrome.storage.sync.get(['glassOpacity'], (syncResult) => {
        if (!chrome.runtime.lastError && syncResult.glassOpacity != null) {
          localStorage.setItem('glassOpacity', String(syncResult.glassOpacity));
        }
        resolve(applyGlassOpacityFromStorage());
      });
    });
  });
}

// Apply as early as possible from localStorage, then refine from chrome.storage
applyThemeAccentFromStorage();
applyPageBackgroundFromStorage();
restoreThemeAccentFromChromeStorage();
applyGlassOpacityFromStorage();
restoreGlassOpacityFromChromeStorage();

window.applyThemeAccent = applyThemeAccent;
window.applyCustomThemeAccent = applyCustomThemeAccent;
window.applyPageBackground = applyPageBackground;
window.applyCustomPageBackground = applyCustomPageBackground;
window.applyThemeAccentFromStorage = applyThemeAccentFromStorage;
window.applyPageBackgroundFromStorage = applyPageBackgroundFromStorage;
window.restoreThemeAccentFromChromeStorage = restoreThemeAccentFromChromeStorage;
window.markWallpaperBackgroundMode = markWallpaperBackgroundMode;
window.persistThemePreference = persistThemePreference;
window.getCustomThemeColor = getCustomThemeColor;
window.getCustomBackgroundColor = getCustomBackgroundColor;
window.isCustomThemeAccentActive = isCustomThemeAccentActive;
window.BACKGROUND_ACCENTS = BACKGROUND_ACCENTS;
window.normalizeThemeHex = normalizeHex;
window.CUSTOM_THEME_BG_CLASS = CUSTOM_BG_CLASS;
window.applyGlassOpacity = applyGlassOpacity;
window.applyGlassOpacityFromStorage = applyGlassOpacityFromStorage;
window.DEFAULT_GLASS_OPACITY = DEFAULT_GLASS_OPACITY;
