import { createErrorResponse, ToolResult } from '@/common/tool-handler';
import { BaseBrowserToolExecutor } from '../base-browser';
import { TOOL_NAMES } from 'chrome-mcp-shared';

// Default window dimensions - optimized for automation tools
const DEFAULT_WINDOW_WIDTH = 1280;
const DEFAULT_WINDOW_HEIGHT = 720;

interface NavigateToolParams {
  url?: string;
  newWindow?: boolean;
  backgroundPage?: boolean;
  width?: number;
  height?: number;
  refresh?: boolean;
}

/**
 * Helper function to create automation-friendly background windows
 * Ensures proper dimensions and timing for web automation tools
 */
async function createAutomationFriendlyBackgroundWindow(
  url: string,
  width: number,
  height: number,
): Promise<chrome.windows.Window | null> {
  try {
    console.log(`Creating automation-friendly background window: ${width}x${height} for ${url}`);

    // Create window with optimal settings for automation
    const window = await chrome.windows.create({
      url: url,
      width: width,
      height: height,
      focused: false, // Don't steal focus from user
      state: chrome.windows.WindowState.NORMAL, // Start in normal state
      type: 'normal', // Normal window type for full automation compatibility
      // Ensure window is created with proper viewport
      left: 0, // Position consistently for automation
      top: 0,
    });

    if (window && window.id !== undefined) {
      // Wait for window to be properly established
      await new Promise((resolve) => setTimeout(resolve, 1500));

      // Verify window still exists and has correct dimensions
      const windowInfo = await chrome.windows.get(window.id);
      if (windowInfo && windowInfo.width === width && windowInfo.height === height) {
        console.log(`Background window ${window.id} established with correct dimensions`);
        return window;
      } else {
        console.warn(`Window ${window.id} dimensions may not be correct`);
        return window; // Return anyway, might still work
      }
    }

    return null;
  } catch (error) {
    console.error('Failed to create automation-friendly background window:', error);
    return null;
  }
}

/**
 * Tool for navigating to URLs in browser tabs or windows
 */
class NavigateTool extends BaseBrowserToolExecutor {
  name = TOOL_NAMES.BROWSER.NAVIGATE;

  async execute(args: NavigateToolParams): Promise<ToolResult> {
    // Check if backgroundPage was explicitly provided, if not, check user settings
    let backgroundPage = args.backgroundPage;
    if (backgroundPage === undefined) {
      try {
        const result = await chrome.storage.local.get(['openUrlsInBackground']);
        // Default to true for background windows (changed from false to true)
        backgroundPage =
          result.openUrlsInBackground !== undefined ? result.openUrlsInBackground : true;
        console.log(`Using stored background page preference: ${backgroundPage}`);
      } catch (error) {
        console.warn('Failed to load background page preference, using default (true):', error);
        backgroundPage = true; // Default to background windows
      }
    }

    const { newWindow = false, width, height, url, refresh = false } = args;

    console.log(
      `Attempting to ${refresh ? 'refresh current tab' : `open URL: ${url}`} with options:`,
      { ...args, backgroundPage },
    );

    try {
      // Handle refresh option first
      if (refresh) {
        console.log('Refreshing current active tab');

        // Get current active tab
        const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true });

        if (!activeTab || !activeTab.id) {
          return createErrorResponse('No active tab found to refresh');
        }

        // Reload the tab
        await chrome.tabs.reload(activeTab.id);

        console.log(`Refreshed tab ID: ${activeTab.id}`);

        // Get updated tab information
        const updatedTab = await chrome.tabs.get(activeTab.id);

        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                success: true,
                message: 'Successfully refreshed current tab',
                tabId: updatedTab.id,
                windowId: updatedTab.windowId,
                url: updatedTab.url,
              }),
            },
          ],
          isError: false,
        };
      }

      // Validate that url is provided when not refreshing
      if (!url) {
        return createErrorResponse('URL parameter is required when refresh is not true');
      }

      // 1. Check if URL is already open
      // Get all tabs and manually compare URLs
      console.log(`Checking if URL is already open: ${url}`);
      // Get all tabs
      const allTabs = await chrome.tabs.query({});
      // Manually filter matching tabs
      const tabs = allTabs.filter((tab) => {
        // Normalize URLs for comparison (remove trailing slashes)
        const tabUrl = tab.url?.endsWith('/') ? tab.url.slice(0, -1) : tab.url;
        const targetUrl = url.endsWith('/') ? url.slice(0, -1) : url;
        return tabUrl === targetUrl;
      });
      console.log(`Found ${tabs.length} matching tabs`);

      if (tabs && tabs.length > 0) {
        const existingTab = tabs[0];
        console.log(
          `URL already open in Tab ID: ${existingTab.id}, Window ID: ${existingTab.windowId}`,
        );

        if (existingTab.id !== undefined) {
          // Activate the tab
          await chrome.tabs.update(existingTab.id, { active: true });

          if (existingTab.windowId !== undefined) {
            // Bring the window containing this tab to the foreground and focus it
            await chrome.windows.update(existingTab.windowId, { focused: true });
          }

          console.log(`Activated existing Tab ID: ${existingTab.id}`);
          // Get updated tab information and return it
          const updatedTab = await chrome.tabs.get(existingTab.id);

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: true,
                  message: 'Activated existing tab',
                  tabId: updatedTab.id,
                  windowId: updatedTab.windowId,
                  url: updatedTab.url,
                }),
              },
            ],
            isError: false,
          };
        }
      }

      // 2. Handle background page option
      if (backgroundPage) {
        console.log(
          'Opening URL in background page using full-size window that will be minimized.',
        );

        const windowWidth = typeof width === 'number' ? width : DEFAULT_WINDOW_WIDTH;
        const windowHeight = typeof height === 'number' ? height : DEFAULT_WINDOW_HEIGHT;

        // Create automation-friendly background window
        const backgroundWindow = await createAutomationFriendlyBackgroundWindow(
          url!,
          windowWidth,
          windowHeight,
        );

        if (backgroundWindow && backgroundWindow.id !== undefined) {
          console.log(
            `Background window created with ID: ${backgroundWindow.id}, dimensions: ${windowWidth}x${windowHeight}`,
          );

          try {
            // Verify window still exists before minimizing
            const windowInfo = await chrome.windows.get(backgroundWindow.id);
            if (windowInfo) {
              console.log(
                `Minimizing window ${backgroundWindow.id} while preserving automation accessibility`,
              );

              // Now minimize the window to keep it in background while maintaining automation accessibility
              await chrome.windows.update(backgroundWindow.id, {
                state: chrome.windows.WindowState.MINIMIZED,
              });

              console.log(
                `URL opened in background Window ID: ${backgroundWindow.id} (${windowWidth}x${windowHeight} then minimized)`,
              );
            }
          } catch (error) {
            console.warn(`Failed to minimize window ${backgroundWindow.id}:`, error);
            // Continue anyway as the window was created successfully
          }

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: true,
                  message:
                    'Opened URL in background page (full-size window then minimized for automation compatibility)',
                  windowId: backgroundWindow.id,
                  width: windowWidth,
                  height: windowHeight,
                  tabs: backgroundWindow.tabs
                    ? backgroundWindow.tabs.map((tab) => ({
                        tabId: tab.id,
                        url: tab.url,
                      }))
                    : [],
                  automationReady: true,
                  minimized: true,
                  dimensions: `${windowWidth}x${windowHeight}`,
                }),
              },
            ],
            isError: false,
          };
        } else {
          console.error('Failed to create automation-friendly background window');
          return createErrorResponse(
            'Failed to create background window with proper automation compatibility',
          );
        }
      }

      // 3. If URL is not already open, decide how to open it based on options
      const openInNewWindow = newWindow || typeof width === 'number' || typeof height === 'number';

      if (openInNewWindow) {
        console.log('Opening URL in a new window.');

        // Create new window
        const newWindow = await chrome.windows.create({
          url: url,
          width: typeof width === 'number' ? width : DEFAULT_WINDOW_WIDTH,
          height: typeof height === 'number' ? height : DEFAULT_WINDOW_HEIGHT,
          focused: true,
        });

        if (newWindow && newWindow.id !== undefined) {
          console.log(`URL opened in new Window ID: ${newWindow.id}`);

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: true,
                  message: 'Opened URL in new window',
                  windowId: newWindow.id,
                  tabs: newWindow.tabs
                    ? newWindow.tabs.map((tab) => ({
                        tabId: tab.id,
                        url: tab.url,
                      }))
                    : [],
                }),
              },
            ],
            isError: false,
          };
        }
      } else {
        console.log('Opening URL in the last active window.');
        // Try to open a new tab in the most recently active window
        const lastFocusedWindow = await chrome.windows.getLastFocused({ populate: false });

        if (lastFocusedWindow && lastFocusedWindow.id !== undefined) {
          console.log(`Found last focused Window ID: ${lastFocusedWindow.id}`);

          const newTab = await chrome.tabs.create({
            url: url,
            windowId: lastFocusedWindow.id,
            active: true,
          });

          // Ensure the window also gets focus
          await chrome.windows.update(lastFocusedWindow.id, { focused: true });

          console.log(
            `URL opened in new Tab ID: ${newTab.id} in existing Window ID: ${lastFocusedWindow.id}`,
          );

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: true,
                  message: 'Opened URL in new tab in existing window',
                  tabId: newTab.id,
                  windowId: lastFocusedWindow.id,
                  url: newTab.url,
                }),
              },
            ],
            isError: false,
          };
        } else {
          // In rare cases, if there's no recently active window (e.g., browser just started with no windows)
          // Fall back to opening in a new window
          console.warn('No last focused window found, falling back to creating a new window.');

          const fallbackWindow = await chrome.windows.create({
            url: url,
            width: DEFAULT_WINDOW_WIDTH,
            height: DEFAULT_WINDOW_HEIGHT,
            focused: true,
          });

          if (fallbackWindow && fallbackWindow.id !== undefined) {
            console.log(`URL opened in fallback new Window ID: ${fallbackWindow.id}`);

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify({
                    success: true,
                    message: 'Opened URL in new window',
                    windowId: fallbackWindow.id,
                    tabs: fallbackWindow.tabs
                      ? fallbackWindow.tabs.map((tab) => ({
                          tabId: tab.id,
                          url: tab.url,
                        }))
                      : [],
                  }),
                },
              ],
              isError: false,
            };
          }
        }
      }

      // If all attempts fail, return a generic error
      return createErrorResponse('Failed to open URL: Unknown error occurred');
    } catch (error) {
      if (chrome.runtime.lastError) {
        console.error(`Chrome API Error: ${chrome.runtime.lastError.message}`, error);
        return createErrorResponse(`Chrome API Error: ${chrome.runtime.lastError.message}`);
      } else {
        console.error('Error in navigate:', error);
        return createErrorResponse(
          `Error navigating to URL: ${error instanceof Error ? error.message : String(error)}`,
        );
      }
    }
  }
}
export const navigateTool = new NavigateTool();

interface CloseTabsToolParams {
  tabIds?: number[];
  url?: string;
}

/**
 * Tool for closing browser tabs
 */
class CloseTabsTool extends BaseBrowserToolExecutor {
  name = TOOL_NAMES.BROWSER.CLOSE_TABS;

  async execute(args: CloseTabsToolParams): Promise<ToolResult> {
    const { tabIds, url } = args;
    let urlPattern = url;
    console.log(`Attempting to close tabs with options:`, args);

    try {
      // If URL is provided, close all tabs matching that URL
      if (urlPattern) {
        console.log(`Searching for tabs with URL: ${url}`);
        if (!urlPattern.endsWith('/')) {
          urlPattern += '/*';
        }
        const tabs = await chrome.tabs.query({ url });

        if (!tabs || tabs.length === 0) {
          console.log(`No tabs found with URL: ${url}`);
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: false,
                  message: `No tabs found with URL: ${url}`,
                  closedCount: 0,
                }),
              },
            ],
            isError: false,
          };
        }

        console.log(`Found ${tabs.length} tabs with URL: ${url}`);
        const tabIdsToClose = tabs
          .map((tab) => tab.id)
          .filter((id): id is number => id !== undefined);

        if (tabIdsToClose.length === 0) {
          return createErrorResponse('Found tabs but could not get their IDs');
        }

        await chrome.tabs.remove(tabIdsToClose);

        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                success: true,
                message: `Closed ${tabIdsToClose.length} tabs with URL: ${url}`,
                closedCount: tabIdsToClose.length,
                closedTabIds: tabIdsToClose,
              }),
            },
          ],
          isError: false,
        };
      }

      // If tabIds are provided, close those tabs
      if (tabIds && tabIds.length > 0) {
        console.log(`Closing tabs with IDs: ${tabIds.join(', ')}`);

        // Verify that all tabIds exist
        const existingTabs = await Promise.all(
          tabIds.map(async (tabId) => {
            try {
              return await chrome.tabs.get(tabId);
            } catch (error) {
              console.warn(`Tab with ID ${tabId} not found`);
              return null;
            }
          }),
        );

        const validTabIds = existingTabs
          .filter((tab): tab is chrome.tabs.Tab => tab !== null)
          .map((tab) => tab.id)
          .filter((id): id is number => id !== undefined);

        if (validTabIds.length === 0) {
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: false,
                  message: 'None of the provided tab IDs exist',
                  closedCount: 0,
                }),
              },
            ],
            isError: false,
          };
        }

        await chrome.tabs.remove(validTabIds);

        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                success: true,
                message: `Closed ${validTabIds.length} tabs`,
                closedCount: validTabIds.length,
                closedTabIds: validTabIds,
                invalidTabIds: tabIds.filter((id) => !validTabIds.includes(id)),
              }),
            },
          ],
          isError: false,
        };
      }

      // If no tabIds or URL provided, close the current active tab
      console.log('No tabIds or URL provided, closing active tab');
      const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true });

      if (!activeTab || !activeTab.id) {
        return createErrorResponse('No active tab found');
      }

      await chrome.tabs.remove(activeTab.id);

      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              success: true,
              message: 'Closed active tab',
              closedCount: 1,
              closedTabIds: [activeTab.id],
            }),
          },
        ],
        isError: false,
      };
    } catch (error) {
      console.error('Error in CloseTabsTool.execute:', error);
      return createErrorResponse(
        `Error closing tabs: ${error instanceof Error ? error.message : String(error)}`,
      );
    }
  }
}

export const closeTabsTool = new CloseTabsTool();

interface GoBackOrForwardToolParams {
  isForward?: boolean;
}

/**
 * Tool for navigating back or forward in browser history
 */
class GoBackOrForwardTool extends BaseBrowserToolExecutor {
  name = TOOL_NAMES.BROWSER.GO_BACK_OR_FORWARD;

  async execute(args: GoBackOrForwardToolParams): Promise<ToolResult> {
    const { isForward = false } = args;

    console.log(`Attempting to navigate ${isForward ? 'forward' : 'back'} in browser history`);

    try {
      // Get current active tab
      const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true });

      if (!activeTab || !activeTab.id) {
        return createErrorResponse('No active tab found');
      }

      // Navigate back or forward based on the isForward parameter
      if (isForward) {
        await chrome.tabs.goForward(activeTab.id);
        console.log(`Navigated forward in tab ID: ${activeTab.id}`);
      } else {
        await chrome.tabs.goBack(activeTab.id);
        console.log(`Navigated back in tab ID: ${activeTab.id}`);
      }

      // Get updated tab information
      const updatedTab = await chrome.tabs.get(activeTab.id);

      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              success: true,
              message: `Successfully navigated ${isForward ? 'forward' : 'back'} in browser history`,
              tabId: updatedTab.id,
              windowId: updatedTab.windowId,
              url: updatedTab.url,
            }),
          },
        ],
        isError: false,
      };
    } catch (error) {
      if (chrome.runtime.lastError) {
        console.error(`Chrome API Error: ${chrome.runtime.lastError.message}`, error);
        return createErrorResponse(`Chrome API Error: ${chrome.runtime.lastError.message}`);
      } else {
        console.error('Error in GoBackOrForwardTool.execute:', error);
        return createErrorResponse(
          `Error navigating ${isForward ? 'forward' : 'back'}: ${
            error instanceof Error ? error.message : String(error)
          }`,
        );
      }
    }
  }
}

export const goBackOrForwardTool = new GoBackOrForwardTool();
