/**
 * Cross-browser API abstraction layer
 * Provides a unified API that works with Chrome, Firefox, and Safari extensions
 * 
 * Note: Safari uses the chrome.* namespace (like Chrome), so most code works
 * without modification. However, Safari requires a native app wrapper for distribution.
 */

// Detect which browser API is available
const browserAPI = (() => {
  // Firefox uses browser.* namespace (and also supports chrome.* for compatibility)
  // Chrome uses chrome.* namespace
  // We prefer browser.* if available (Firefox), otherwise fall back to chrome.*
  if (typeof browser !== 'undefined' && browser.runtime && browser.runtime.getBrowserInfo) {
    // Firefox - browser API is available
    return browser;
  } else if (typeof chrome !== 'undefined' && chrome.runtime) {
    // Chrome - chrome API is available
    return chrome;
  } else if (typeof browser !== 'undefined' && browser.runtime) {
    // Firefox with browser API (but getBrowserInfo might not be available in all contexts)
    return browser;
  }
  
  // Return a mock object if no browser extension API is available
  // This allows the code to run in regular web pages without throwing errors
  return {
    runtime: undefined,
    storage: undefined,
    tabs: undefined,
    windows: undefined,
    action: undefined,
    browserAction: undefined,
  };
})();

/**
 * Get the browser name (chrome, firefox, or safari)
 */
export function getBrowserName() {
  if (typeof browser !== 'undefined' && browser.runtime) {
    try {
      // Firefox has getBrowserInfo, Chrome doesn't
      if (browser.runtime.getBrowserInfo) {
        return 'firefox';
      }
    } catch (e) {
      // getBrowserInfo might not be available in all contexts
    }
    // If browser API exists but getBrowserInfo doesn't work, check other indicators
    if (typeof chrome === 'undefined' || !chrome.runtime) {
      return 'firefox';
    }
  }
  
  // Safari uses chrome.* namespace, so we need to detect it differently
  // Safari can be detected by checking user agent (in content scripts)
  // or by checking for Safari-specific properties
  if (typeof chrome !== 'undefined' && chrome.runtime) {
    try {
      // In content scripts, we can check navigator.userAgent
      if (typeof navigator !== 'undefined' && navigator.userAgent) {
        const ua = navigator.userAgent;
        // Safari user agent contains "Safari" but not "Chrome" (Chrome also has Safari in UA)
        if (ua.includes('Safari') && !ua.includes('Chrome') && !ua.includes('Chromium')) {
          return 'safari';
        }
      }
      
      // Safari may have different manifest structure or properties
      // Check if we're in a Safari extension context
      // Note: This is a best-effort detection, Safari uses chrome.* so it's hard to distinguish
    } catch (e) {
      // Ignore errors during detection
    }
  }
  
  // Default to chrome (Safari also uses chrome.* namespace)
  return 'chrome';
}

/**
 * Storage API abstraction
 */
export const storage = {
  local: {
    get: (keys) => {
      if (!browserAPI.storage || !browserAPI.storage.local) {
        throw new Error('Storage API is not available in this context');
      }
      return new Promise((resolve, reject) => {
        browserAPI.storage.local.get(keys, (result) => {
          const error = browserAPI.runtime.lastError;
          if (error) {
            reject(new Error(error.message || 'Storage error'));
          } else {
            resolve(result);
          }
        });
      });
    },
    set: (items) => {
      if (!browserAPI.storage || !browserAPI.storage.local) {
        throw new Error('Storage API is not available in this context');
      }
      return new Promise((resolve, reject) => {
        browserAPI.storage.local.set(items, () => {
          const error = browserAPI.runtime.lastError;
          if (error) {
            reject(new Error(error.message || 'Storage error'));
          } else {
            resolve();
          }
        });
      });
    },
    remove: (keys) => {
      if (!browserAPI.storage || !browserAPI.storage.local) {
        throw new Error('Storage API is not available in this context');
      }
      return new Promise((resolve, reject) => {
        browserAPI.storage.local.remove(keys, () => {
          const error = browserAPI.runtime.lastError;
          if (error) {
            reject(new Error(error.message || 'Storage error'));
          } else {
            resolve();
          }
        });
      });
    },
    clear: () => {
      if (!browserAPI.storage || !browserAPI.storage.local) {
        throw new Error('Storage API is not available in this context');
      }
      return new Promise((resolve, reject) => {
        browserAPI.storage.local.clear(() => {
          const error = browserAPI.runtime.lastError;
          if (error) {
            reject(new Error(error.message || 'Storage error'));
          } else {
            resolve();
          }
        });
      });
    },
    get onChanged() {
      if (!browserAPI.storage) {
        return undefined;
      }
      return browserAPI.storage.onChanged;
    },
  },
  session: {
    get: (keys) => {
      if (!browserAPI.storage) {
        throw new Error('Storage API is not available in this context');
      }
      return new Promise((resolve, reject) => {
        // Firefox might not have session storage in older versions
        // Fall back to local storage if session is not available
        const storageArea = browserAPI.storage.session || browserAPI.storage.local;
        if (!storageArea) {
          reject(new Error('Storage API is not available in this context'));
          return;
        }
        storageArea.get(keys, (result) => {
          const error = browserAPI.runtime.lastError;
          if (error) {
            reject(new Error(error.message || 'Storage error'));
          } else {
            resolve(result);
          }
        });
      });
    },
    set: (items) => {
      if (!browserAPI.storage) {
        throw new Error('Storage API is not available in this context');
      }
      return new Promise((resolve, reject) => {
        const storageArea = browserAPI.storage.session || browserAPI.storage.local;
        if (!storageArea) {
          reject(new Error('Storage API is not available in this context'));
          return;
        }
        storageArea.set(items, () => {
          const error = browserAPI.runtime.lastError;
          if (error) {
            reject(new Error(error.message || 'Storage error'));
          } else {
            resolve();
          }
        });
      });
    },
    clear: () => {
      if (!browserAPI.storage) {
        throw new Error('Storage API is not available in this context');
      }
      return new Promise((resolve, reject) => {
        const storageArea = browserAPI.storage.session || browserAPI.storage.local;
        if (!storageArea) {
          reject(new Error('Storage API is not available in this context'));
          return;
        }
        storageArea.clear(() => {
          const error = browserAPI.runtime.lastError;
          if (error) {
            reject(new Error(error.message || 'Storage error'));
          } else {
            resolve();
          }
        });
      });
    },
    get onChanged() {
      if (!browserAPI.storage) {
        return undefined;
      }
      return browserAPI.storage.session?.onChanged || browserAPI.storage.onChanged;
    },
  },
};

/**
 * Runtime API abstraction
 */
export const runtime = {
  get id() {
    if (!browserAPI.runtime) {
      return undefined;
    }
    return browserAPI.runtime.id;
  },
  getURL: (path) => {
    if (!browserAPI.runtime) {
      throw new Error('Runtime API is not available in this context');
    }
    return browserAPI.runtime.getURL(path);
  },
  sendMessage: (message, responseCallback) => {
    if (!browserAPI.runtime) {
      throw new Error('Runtime API is not available in this context');
    }
    return browserAPI.runtime.sendMessage(message, responseCallback);
  },
  get onMessage() {
    if (!browserAPI.runtime) {
      return undefined;
    }
    return browserAPI.runtime.onMessage;
  },
  get onStartup() {
    if (!browserAPI.runtime) {
      return undefined;
    }
    return browserAPI.runtime.onStartup;
  },
  get onInstalled() {
    if (!browserAPI.runtime) {
      return undefined;
    }
    return browserAPI.runtime.onInstalled;
  },
  connect: (connectInfo) => {
    if (!browserAPI.runtime) {
      throw new Error('Runtime API is not available in this context');
    }
    return browserAPI.runtime.connect(connectInfo);
  },
  getPlatformInfo: (callback) => {
    if (!browserAPI.runtime) {
      callback({ os: 'unknown', arch: 'unknown' });
      return;
    }
    if (browserAPI.runtime.getPlatformInfo) {
      return browserAPI.runtime.getPlatformInfo(callback);
    } else {
      // Fallback for browsers that don't support getPlatformInfo
      callback({ os: 'unknown', arch: 'unknown' });
    }
  },
  getManifest: () => {
    if (!browserAPI.runtime) {
      throw new Error('Runtime API is not available in this context');
    }
    return browserAPI.runtime.getManifest();
  },
  get lastError() {
    if (!browserAPI.runtime) {
      return undefined;
    }
    return browserAPI.runtime.lastError;
  },
  openOptionsPage: () => {
    if (!browserAPI.runtime) {
      throw new Error('Runtime API is not available in this context');
    }
    if (browserAPI.runtime.openOptionsPage) {
      browserAPI.runtime.openOptionsPage();
    } else {
      // Fallback: open options page manually
      if (browserAPI.tabs) {
        browserAPI.tabs.create({ url: browserAPI.runtime.getURL('options/index.html') });
      } else {
        throw new Error('Tabs API is not available in this context');
      }
    }
  },
};

/**
 * Tabs API abstraction
 */
export const tabs = {
  query: (queryInfo, callback) => {
    if (!browserAPI.tabs) {
      throw new Error('Tabs API is not available in this context');
    }
    return browserAPI.tabs.query(queryInfo, callback);
  },
  get: (tabId, callback) => {
    if (!browserAPI.tabs) {
      throw new Error('Tabs API is not available in this context');
    }
    return browserAPI.tabs.get(tabId, callback);
  },
  create: (createProperties, callback) => {
    if (!browserAPI.tabs) {
      throw new Error('Tabs API is not available in this context');
    }
    return browserAPI.tabs.create(createProperties, callback);
  },
  sendMessage: (tabId, message, responseCallback) => {
    if (!browserAPI.tabs) {
      throw new Error('Tabs API is not available in this context');
    }
    return browserAPI.tabs.sendMessage(tabId, message, responseCallback);
  },
  get onUpdated() {
    if (!browserAPI.tabs) {
      return undefined;
    }
    return browserAPI.tabs.onUpdated;
  },
};

/**
 * Action API abstraction (Chrome uses action, Firefox uses browserAction in older versions)
 */
export const action = {
  setBadgeText: (details, callback) => {
    if (browserAPI.action) {
      return browserAPI.action.setBadgeText(details, callback);
    } else if (browserAPI.browserAction) {
      return browserAPI.browserAction.setBadgeText(details, callback);
    }
  },
  setBadgeBackgroundColor: (details, callback) => {
    if (browserAPI.action) {
      return browserAPI.action.setBadgeBackgroundColor(details, callback);
    } else if (browserAPI.browserAction) {
      return browserAPI.browserAction.setBadgeBackgroundColor(details, callback);
    }
  },
};

/**
 * Windows API abstraction
 */
export const windows = {
  create: (createData, callback) => {
    if (!browserAPI.windows) {
      throw new Error('Windows API is not available in this context');
    }
    return browserAPI.windows.create(createData, callback);
  },
  getAll: (getInfo, callback) => {
    if (!browserAPI.windows) {
      throw new Error('Windows API is not available in this context');
    }
    return browserAPI.windows.getAll(getInfo, callback);
  },
  get onRemoved() {
    if (!browserAPI.windows) {
      return undefined;
    }
    return browserAPI.windows.onRemoved;
  },
};

// Export the detected browser API for advanced usage
export { browserAPI };

