import { dispatch } from '../lib/page-rpc';

export default defineContentScript({
  matches: ['http://*/*', 'https://*/*'],
  runAt: 'document_idle',
  async main() {
    const autoInjectResult = await chrome.storage.local.get('muyue_auto_inject');
    if (!autoInjectResult.muyue_auto_inject) return;
    if (window.__muyueExtension) return;
    window.__muyueExtension = true;

    let ws = null;
    let retryDelay = 0;
    let token = null;
    let wsBaseUrl = null;
    const TAG = '[Muyue]';

    function log(...args) {
      console.log(TAG, ...args);
    }

    function send(obj) {
      try {
        if (ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(obj));
      } catch {}
    }

    function reply(id, data) {
      send({ type: 'reply', id, data });
    }

    function sendConsole(level, text) {
      send({ type: 'console', level, text });
    }

    async function getToken() {
      return new Promise((resolve) => {
        chrome.runtime.sendMessage({ type: 'get_token' }, (response) => {
          if (chrome.runtime.lastError) {
            resolve(null);
            return;
          }
          resolve(response);
        });
      });
    }

    function screenshotNative(params) {
      return new Promise((resolve) => {
        chrome.runtime.sendMessage({ type: 'screenshot', params }, (response) => {
          if (chrome.runtime.lastError) {
            resolve({ ok: false, error: String(chrome.runtime.lastError) });
            return;
          }
          resolve(response || { ok: false, error: 'no response' });
        });
      });
    }

    async function connect() {
      if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
        return;
      }

      if (!token) {
        const data = await getToken();
        if (!data) {
          retryDelay = Math.min(retryDelay + 1, 5);
          setTimeout(connect, 1000 * retryDelay);
          return;
        }
        token = data.token;
        wsBaseUrl = data.wsUrl;
      }

      try {
        const wsUrl = wsBaseUrl || `ws://127.0.0.1:8080/api/ws/browser-test?token=${token}`;
        ws = new WebSocket(wsUrl);
      } catch {
        retryDelay = Math.min(retryDelay + 1, 5);
        setTimeout(connect, 1000 * retryDelay);
        return;
      }

      ws.onopen = () => {
        retryDelay = 0;
        send({ type: 'hello', url: location.href, title: document.title });
        log('connected to Muyue server');
      };

      ws.onmessage = (ev) => {
        let msg;
        try { msg = JSON.parse(ev.data); } catch { return; }

        if (msg.type === 'registered') {
          log('session registered:', msg.session_id);
          return;
        }

        if (msg.action) {
          if (msg.action === 'screenshot') {
            screenshotNative(msg.params || {}).then((r) => reply(msg.id, r));
            return;
          }
          const result = dispatch(msg);
          if (result && typeof result.then === 'function') {
            result.then((r) => reply(msg.id, r));
          } else {
            reply(msg.id, result);
          }
        }
      };

      ws.onclose = () => {
        retryDelay = Math.min(retryDelay + 1, 5);
        setTimeout(connect, 500 * retryDelay);
      };

      ws.onerror = () => {};
    }

    ['log', 'info', 'warn', 'error', 'debug'].forEach((lvl) => {
      const orig = console[lvl];
      console[lvl] = function () {
        try {
          const parts = Array.from(arguments).map((a) => {
            if (typeof a === 'string') return a;
            try { return JSON.stringify(a); } catch { return String(a); }
          });
          const text = parts.join(' ');
          if (!text.startsWith(TAG)) {
            sendConsole(lvl, text);
            if (lvl === 'error') {
              chrome.runtime.sendMessage({ type: 'increment_errors' }).catch(() => {});
            }
          }
        } catch {}
        return orig.apply(console, arguments);
      };
    });

    window.addEventListener('error', (e) => {
      sendConsole('error', 'window.onerror: ' + (e.message || 'unknown'));
      chrome.runtime.sendMessage({ type: 'increment_errors' }).catch(() => {});
    });

    window.addEventListener('unhandledrejection', (e) => {
      sendConsole('error', 'unhandledrejection: ' + String(e.reason));
      chrome.runtime.sendMessage({ type: 'increment_errors' }).catch(() => {});
    });

    let lastUrl = location.href;
    const urlObserver = new MutationObserver(() => {
      if (location.href !== lastUrl) {
        lastUrl = location.href;
        send({ type: 'url_change', url: lastUrl });
      }
    });
    urlObserver.observe(document.documentElement, { childList: true, subtree: true });

    const origPushState = history.pushState;
    history.pushState = function () {
      origPushState.apply(this, arguments);
      if (location.href !== lastUrl) {
        lastUrl = location.href;
        send({ type: 'url_change', url: lastUrl });
      }
    };

    const origReplaceState = history.replaceState;
    history.replaceState = function () {
      origReplaceState.apply(this, arguments);
      if (location.href !== lastUrl) {
        lastUrl = location.href;
        send({ type: 'url_change', url: lastUrl });
      }
    };

    window.addEventListener('popstate', () => {
      if (location.href !== lastUrl) {
        lastUrl = location.href;
        send({ type: 'url_change', url: lastUrl });
      }
    });

    setInterval(() => {
      if (location.href !== lastUrl) {
        lastUrl = location.href;
        send({ type: 'url_change', url: lastUrl });
      }
    }, 500);

    connect();
  },
});
