/**
 * AI website introduction for bookmark links.
 */

import { callHostedAiChat, PRO_FEATURES } from './membership.js';
import { renderSimpleMarkdown } from './markdown-utils.js';
import {
  loadAiOrganizeSettings,
  canRunAiOrganize,
  ensureAiHostPermission,
  isHostedAiProvider,
  resolveHostedModel
} from './ai-bookmark-organize.js';

function i18n(key, fallback, substitutions) {
  const msg = chrome.i18n.getMessage(key, substitutions);
  return msg || fallback || key;
}

function normalizeBaseUrl(baseUrl) {
  return String(baseUrl || '').trim().replace(/\/+$/, '');
}

function buildAiRequestHeaders(settings) {
  const headers = {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${String(settings.apiKey || '').trim()}`
  };
  const baseUrl = normalizeBaseUrl(settings.baseUrl);
  if (settings.provider === 'openrouter' || baseUrl.includes('openrouter.ai')) {
    headers['HTTP-Referer'] = chrome.runtime.getURL('src/index.html');
    headers['X-Title'] = 'SuperMark';
  }
  return headers;
}

function normalizeIntroduction(text) {
  const cleaned = String(text || '').trim();
  if (!cleaned || cleaned === '[object Object]') {
    throw new Error('EMPTY_AI_RESPONSE');
  }
  return cleaned.replace(/^```(?:markdown|md|text)?\s*/i, '').replace(/\s*```$/i, '').trim();
}

function extractJsonObject(text) {
  if (text && typeof text === 'object') return text;
  const trimmed = String(text || '').trim();
  if (!trimmed || trimmed === '[object Object]') {
    throw new Error('EMPTY_AI_RESPONSE');
  }
  const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
  const candidate = fenced ? fenced[1].trim() : trimmed;
  const start = candidate.indexOf('{');
  const end = candidate.lastIndexOf('}');
  if (start === -1 || end === -1 || end <= start) {
    throw new Error('INVALID_AI_JSON');
  }
  return JSON.parse(candidate.slice(start, end + 1));
}

function parseIntroductionPayload(raw) {
  if (typeof raw === 'string') {
    return normalizeIntroduction(raw);
  }
  const intro = String(
    raw?.introduction
    || raw?.summary
    || raw?.description
    || raw?.content
    || ''
  ).trim();
  if (!intro) {
    throw new Error('EMPTY_AI_RESPONSE');
  }
  return normalizeIntroduction(intro);
}

function buildIntroducePrompt(title, url, localeHint) {
  return [
    `Introduce the following website to the user in ${localeHint}.`,
    `Website title: ${title}`,
    `URL: ${url}`,
    '',
    'Return JSON only with this shape:',
    '{"introduction":"markdown introduction here"}',
    '',
    'Write a helpful, concise introduction (about 120-250 words) in the introduction field, covering:',
    '- What the site is and what it offers',
    '- Who it is useful for',
    '- Notable features or strengths',
    '- Any widely known caveats (if applicable)',
    '',
    'Use Markdown inside the introduction string (headings, bullet lists, **bold**, links).',
    'Do not invent specific facts you are unsure about; note uncertainty when needed.',
    'Respond in the user locale language when possible.'
  ].join('\n');
}

async function callHostedIntroduce(title, url, settings) {
  const localeHint = (chrome.i18n.getUILanguage() || 'en').replace('_', '-');
  const model = resolveHostedModel(settings);
  const data = await callHostedAiChat({
    temperature: 0.35,
    maxTokens: 900,
    model,
    feature: PRO_FEATURES.AI_INTRODUCE,
    messages: [
      {
        role: 'system',
        content: 'You are a helpful web guide. Respond with JSON only.'
      },
      {
        role: 'user',
        content: buildIntroducePrompt(title, url, localeHint)
      }
    ]
  });
  const content = data?.choices?.[0]?.message?.content;
  return parseIntroductionPayload(extractJsonObject(content));
}

async function callByokIntroduceOnce(title, url, settings, { jsonMode }) {
  const localeHint = (chrome.i18n.getUILanguage() || 'en').replace('_', '-');
  const endpoint = `${normalizeBaseUrl(settings.baseUrl)}/chat/completions`;
  const body = {
    model: settings.model.trim(),
    temperature: 0.35,
    messages: [
      {
        role: 'system',
        content: 'You are a helpful web guide. Respond with JSON only.'
      },
      {
        role: 'user',
        content: buildIntroducePrompt(title, url, localeHint)
      }
    ]
  };
  if (jsonMode) {
    body.response_format = { type: 'json_object' };
  }

  const response = await fetch(endpoint, {
    method: 'POST',
    headers: buildAiRequestHeaders(settings),
    body: JSON.stringify(body)
  });

  if (!response.ok) {
    let detail = '';
    try {
      const errBody = await response.json();
      detail = errBody?.error?.message || errBody?.message || '';
    } catch {
      detail = await response.text().catch(() => '');
    }
    const error = new Error(detail || `HTTP_${response.status}`);
    error.status = response.status;
    throw error;
  }

  const data = await response.json();
  const content = data?.choices?.[0]?.message?.content;
  return parseIntroductionPayload(extractJsonObject(content));
}

async function callByokIntroduce(title, url, settings) {
  try {
    return await callByokIntroduceOnce(title, url, settings, { jsonMode: true });
  } catch (error) {
    if (
      String(error.message || '').toLowerCase().includes('response_format')
      || error.status === 400
    ) {
      return callByokIntroduceOnce(title, url, settings, { jsonMode: false });
    }
    throw error;
  }
}

export async function fetchWebsiteIntroduction({ title, url }) {
  const siteTitle = String(title || '').trim().slice(0, 200) || String(url || '').trim();
  const siteUrl = String(url || '').trim();
  if (!siteUrl) {
    throw new Error('URL_REQUIRED');
  }

  const settings = await loadAiOrganizeSettings();
  const readiness = await canRunAiOrganize(settings, { aiFeature: PRO_FEATURES.AI_INTRODUCE });
  if (!readiness.ok) {
    throw new Error(readiness.reason || 'AI_NOT_CONFIGURED');
  }

  const useHosted = readiness.mode === 'hosted' || isHostedAiProvider(settings);

  if (useHosted) {
    try {
      const hostedSettings = await loadAiOrganizeSettings();
      return await callHostedIntroduce(siteTitle, siteUrl, hostedSettings);
    } catch (error) {
      const code = error.code || error.message;
      if (
        (code === 'quota_exceeded' || code === 'quota_none' || error.status === 429 || error.status === 403)
        && String(settings.apiKey || '').trim()
        && !isHostedAiProvider(settings)
      ) {
        // Fall through to BYOK
      } else if (code === 'quota_exceeded' || code === 'quota_none') {
        throw new Error(code === 'quota_none' ? 'AI_QUOTA_NONE' : 'AI_QUOTA_EXCEEDED');
      } else if (code === 'NOT_SIGNED_IN') {
        throw new Error('NOT_SIGNED_IN');
      } else if (code === 'invalid_model' || code === 'MODEL_REQUIRED') {
        throw new Error('AI_NOT_CONFIGURED');
      } else {
        throw error;
      }
    }
  }

  if (!String(settings.apiKey || '').trim() || isHostedAiProvider(settings)) {
    throw new Error('AI_NOT_CONFIGURED');
  }

  const granted = await ensureAiHostPermission(settings.baseUrl);
  if (!granted) throw new Error('PERMISSION_DENIED');
  return callByokIntroduce(siteTitle, siteUrl, settings);
}

const LOADING_STEP_INTERVAL_MS = 2400;

function getIntroduceLoadingSteps() {
  return [
    i18n('aiIntroduceThinking', 'AI is analyzing this website…'),
    i18n('aiIntroduceLoadingContext', 'Gathering site context…'),
    i18n('aiIntroduceLoadingDraft', 'Drafting introduction…')
  ];
}

function setIntroduceLoadingState({
  loadingEl,
  contentEl,
  loadingTextEl,
  statusEl,
  isLoading
}) {
  if (loadingEl) {
    loadingEl.hidden = !isLoading;
    loadingEl.setAttribute('aria-busy', isLoading ? 'true' : 'false');
  }
  if (contentEl) {
    contentEl.hidden = isLoading;
    contentEl.classList.remove('is-loading');
  }
  if (statusEl) {
    statusEl.hidden = isLoading;
    if (isLoading) {
      statusEl.textContent = '';
      statusEl.classList.remove('is-error');
    }
  }
  if (loadingTextEl && isLoading) {
    loadingTextEl.textContent = getIntroduceLoadingSteps()[0];
  }
}

function startIntroduceLoadingTicker(loadingTextEl) {
  const steps = getIntroduceLoadingSteps();
  let stepIndex = 0;
  if (loadingTextEl) {
    loadingTextEl.textContent = steps[0];
  }
  return window.setInterval(() => {
    stepIndex = (stepIndex + 1) % steps.length;
    if (loadingTextEl) {
      loadingTextEl.textContent = steps[stepIndex];
    }
  }, LOADING_STEP_INTERVAL_MS);
}

function renderIntroductionContent(contentEl, markdown) {
  if (!contentEl) return;
  contentEl.innerHTML = renderSimpleMarkdown(markdown);
}

export function getAiIntroduceErrorMessage(error) {
  const code = String(error?.code || error?.message || error || '');
  if (code === 'URL_REQUIRED') {
    return i18n('aiIntroduceUrlRequired', 'Bookmark URL is missing');
  }
  if (code === 'NOT_SIGNED_IN') {
    return i18n('aiOrganizeNeedSignIn', 'Sign in to use SuperMark hosted AI');
  }
  if (code === 'AI_QUOTA_EXCEEDED' || code === 'AI_QUOTA_NONE') {
    return i18n(
      'aiOrganizeQuotaExceeded',
      'Monthly hosted AI quota used up. Upgrade or use your own API key.'
    );
  }
  if (code === 'AI_NOT_CONFIGURED') {
    return i18n('aiOrganizeNeedConfig', 'Please configure AI API in Settings → AI first');
  }
  if (code === 'PERMISSION_DENIED') {
    return i18n('aiOrganizePermissionDenied', 'Network permission denied for the AI API');
  }
  if (code === 'EMPTY_AI_RESPONSE') {
    return i18n('aiIntroduceInvalidResponse', 'AI returned an empty introduction');
  }
  if (code === 'INVALID_AI_JSON') {
    return i18n('aiIntroduceInvalidResponse', 'AI returned an empty introduction');
  }
  if (code === 'ai_upstream_error') {
    const detail = String(error?.messageDetail || error?.message || '').trim();
    if (detail && detail !== code) {
      return i18n('aiIntroduceError', 'AI introduction failed: $1', [detail.slice(0, 120)]);
    }
  }
  return i18n(
    'aiIntroduceError',
    'AI introduction failed: $1',
    [code.slice(0, 120)]
  );
}

/**
 * Show introduction dialog and fetch AI content for a bookmark.
 * @returns {Promise<string|null>} introduction text or null if cancelled
 */
export function showWebsiteIntroduceDialog({ title, url }) {
  return new Promise((resolve) => {
    const dialog = document.getElementById('ai-introduce-dialog');
    const titleEl = document.getElementById('ai-introduce-site-title');
    const urlEl = document.getElementById('ai-introduce-site-url');
    const loadingEl = document.getElementById('ai-introduce-loading');
    const loadingTextEl = document.getElementById('ai-introduce-loading-text');
    const contentEl = document.getElementById('ai-introduce-content');
    const statusEl = document.getElementById('ai-introduce-status');
    const copyBtn = document.getElementById('ai-introduce-copy-button');
    const openBtn = document.getElementById('ai-introduce-open-button');
    const closeBtn = document.getElementById('ai-introduce-close-button');
    const cancelBtn = document.getElementById('ai-introduce-cancel-button');

    if (!dialog || !contentEl) {
      fetchWebsiteIntroduction({ title, url })
        .then((intro) => {
          window.alert(intro);
          resolve(intro);
        })
        .catch((error) => {
          console.error(error);
          window.alert(getAiIntroduceErrorMessage(error));
          resolve(null);
        });
      return;
    }

    let introduction = '';
    let busy = true;
    let closed = false;
    let loadingTicker = null;

    const stopLoadingTicker = () => {
      if (loadingTicker) {
        window.clearInterval(loadingTicker);
        loadingTicker = null;
      }
    };

    const setStatus = (text, isError = false) => {
      if (!statusEl) return;
      statusEl.hidden = !text;
      statusEl.textContent = text || '';
      statusEl.classList.toggle('is-error', Boolean(isError));
    };

    const cleanup = (result) => {
      if (closed) return;
      closed = true;
      stopLoadingTicker();
      copyBtn?.removeEventListener('click', onCopy);
      openBtn?.removeEventListener('click', onOpen);
      closeBtn?.removeEventListener('click', onClose);
      cancelBtn?.removeEventListener('click', onClose);
      dialog.style.display = 'none';
      resolve(result);
    };

    const onClose = () => {
      cleanup(busy ? null : introduction);
    };

    const onCopy = async () => {
      if (!introduction) return;
      try {
        await navigator.clipboard.writeText(introduction);
        setStatus(i18n('aiIntroduceCopied', 'Introduction copied'));
        window.setTimeout(() => setStatus(''), 1800);
      } catch (error) {
        console.error('Copy failed:', error);
        setStatus(i18n('aiIntroduceCopyFailed', 'Failed to copy'), true);
      }
    };

    const onOpen = () => {
      if (url) window.open(url, '_blank', 'noopener');
    };

    if (titleEl) titleEl.textContent = title || url;
    if (urlEl) {
      urlEl.textContent = url;
      urlEl.href = url;
    }
    if (contentEl) contentEl.innerHTML = '';
    setIntroduceLoadingState({
      loadingEl,
      contentEl,
      loadingTextEl,
      statusEl,
      isLoading: true
    });
    loadingTicker = startIntroduceLoadingTicker(loadingTextEl);
    if (copyBtn) copyBtn.disabled = true;
    dialog.style.display = 'block';

    copyBtn?.addEventListener('click', onCopy);
    openBtn?.addEventListener('click', onOpen);
    closeBtn?.addEventListener('click', onClose);
    cancelBtn?.addEventListener('click', onClose);

    fetchWebsiteIntroduction({ title, url })
      .then((intro) => {
        if (closed) return;
        stopLoadingTicker();
        introduction = intro;
        busy = false;
        if (contentEl) renderIntroductionContent(contentEl, intro);
        setIntroduceLoadingState({
          loadingEl,
          contentEl,
          loadingTextEl,
          statusEl,
          isLoading: false
        });
        if (copyBtn) copyBtn.disabled = false;
        setStatus('');
      })
      .catch((error) => {
        if (closed) return;
        stopLoadingTicker();
        busy = false;
        if (contentEl) contentEl.innerHTML = '';
        setIntroduceLoadingState({
          loadingEl,
          contentEl,
          loadingTextEl,
          statusEl,
          isLoading: false
        });
        setStatus(getAiIntroduceErrorMessage(error), true);
        if (copyBtn) copyBtn.disabled = true;
      });
  });
}
