import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { createAction, Property } from '@activepieces/pieces-framework';
import { serpApiAuth } from '../auth';
import { COUNTRY_OPTIONS } from '../constants/countries';
import { GOOGLE_DOMAIN_OPTIONS } from '../constants/google-domains';
import { LANGUAGE_OPTIONS } from '../constants/languages';
import { SerpApiClient } from '../services/serp-api-client';
import { GoogleSearchConfig, SerpApiEngine } from '../types';

export const googleSearch = createAction({
  auth: serpApiAuth,
  name: 'google_search',
  displayName: 'Google Search',
  description: 'Retrieves organic search results for specific keywords with advanced filtering options for SEO monitoring and competitor analysis.',
  audience: 'both',
  aiMetadata: { description: 'Runs a Google web search via SerpApi and returns organic results for a query. Use to look up current web information, check rankings, or research a topic with controls for location, language, country, device, and pagination. Read-only and idempotent; requires the search query and a SerpApi API key.', idempotent: true },

  props: {
    query: Property.ShortText({
      displayName: 'Search Query',
      description: 'Search query to execute',
      required: true,
    }),

    location_search: Property.ShortText({
      displayName: 'Location Search',
      description: 'Type location name to search',
      required: false,
    }),

    location: Property.Dropdown({
      auth: serpApiAuth,
      displayName: 'Location',
      description: 'Geographic location for results',
      required: false,
      refreshers: ['location_search'],
      options: async ({ auth, location_search }) => {
        if (!auth || !location_search) {
          return {
            disabled: true,
            options: [],
            placeholder: 'Type a location to search...',
          };
        }

        try {
          const response = await httpClient.sendRequest({
            method: HttpMethod.GET,
            url: 'https://serpapi.com/locations.json',
            queryParams: {
              q: location_search as string,
              limit: '10',
            },
          });

          if (response.body && Array.isArray(response.body)) {
            return {
              disabled: false,
              options: response.body.map((location: any) => ({
                label: `${location.name}${location.country ? `, ${location.country}` : ''}`,
                value: location.canonical_name || location.name,
              })),
            };
          }

          return {
            disabled: false,
            options: [],
            placeholder: 'No locations found',
          };
        } catch (error) {
          console.error('Error fetching locations:', error);
          return {
            disabled: false,
            options: [],
            placeholder: 'Error searching locations. Please check your API key.',
          };
        }
      },
    }),

    hl: Property.StaticDropdown({
      displayName: 'Host Language (hl)',
      description: 'Language for search results',
      required: false,
      defaultValue: 'en',
      options: {
        options: LANGUAGE_OPTIONS,
      },
    }),

    google_domain: Property.StaticDropdown({
      displayName: 'Google Domain',
      description: 'Google domain to use',
      required: false,
      defaultValue: 'google.com',
      options: {
        options: GOOGLE_DOMAIN_OPTIONS,
      },
    }),

    gl: Property.StaticDropdown({
      displayName: 'Country (gl)',
      description: 'Country for search results',
      required: false,
      options: {
        options: COUNTRY_OPTIONS,
      },
    }),

    no_cache: Property.StaticDropdown({
      displayName: 'No Cache',
      description: 'Force fresh results',
      required: false,
      defaultValue: 'false',
      options: {
        options: [
          { label: 'false (Allow cache)', value: 'false' },
          { label: 'true (Force fresh results)', value: 'true' },
        ],
      },
    }),

    async: Property.StaticDropdown({
      displayName: 'Async',
      description: 'Submit search asynchronously',
      required: false,
      defaultValue: 'false',
      options: {
        options: [
          { label: 'false (Synchronous)', value: 'false' },
          { label: 'true (Asynchronous)', value: 'true' },
        ],
      },
    }),

    num_results: Property.Number({
      displayName: 'Number of Results',
      description: 'Number of results to return (1-100)',
      required: false,
      defaultValue: 10,
    }),

    start: Property.Number({
      displayName: 'Start Position',
      description: 'Starting position for pagination (0-990)',
      required: false,
      defaultValue: 0,
    }),

    safe: Property.StaticDropdown({
      displayName: 'Safe Search',
      description: 'Safe search filtering level',
      required: false,
      defaultValue: 'active',
      options: {
        options: [
          { label: 'Active (Enabled)', value: 'active' },
          { label: 'Off (Disabled)', value: 'off' },
        ],
      },
    }),

    device: Property.StaticDropdown({
      displayName: 'Device Type',
      description: 'Device type for search simulation',
      required: false,
      defaultValue: 'desktop',
      options: {
        options: [
          { label: 'Desktop', value: 'desktop' },
          { label: 'Mobile', value: 'mobile' },
          { label: 'Tablet', value: 'tablet' },
        ],
      },
    }),

    filter: Property.StaticDropdown({
      displayName: 'Result Filter',
      description: 'Filter duplicate results',
      required: false,
      defaultValue: '0',
      options: {
        options: [
          { label: 'Show similar results', value: '0' },
          { label: 'Hide similar results', value: '1' },
        ],
      },
    }),
  },

  async run({ auth, propsValue }) {
    try {
      // Create SerpApi client with optimal settings
      const client = new SerpApiClient({
        defaultTimeout: 30000,
        defaultRetries: 3,
        defaultRetryDelay: 1000,
        enableLogging: false,
      });

      // Build search configuration
      const searchConfig: GoogleSearchConfig = {
        api_key: auth.secret_text,
        engine: SerpApiEngine.GOOGLE,
        q: propsValue.query,
        hl: propsValue.hl,
        num: propsValue.num_results,
        start: propsValue.start,
        safe: propsValue.safe as 'active' | 'off',
        device: propsValue.device as 'desktop' | 'mobile' | 'tablet',
        filter: propsValue.filter as '0' | '1',
      };

      // Add optional location if provided
      if (propsValue.location) {
        (searchConfig as any).location = propsValue.location;
      }

      // Add optional google_domain if provided
      if (propsValue.google_domain) {
        (searchConfig as any).google_domain = propsValue.google_domain;
      }

      // Add optional gl (country) if provided
      if (propsValue.gl) {
        (searchConfig as any).gl = propsValue.gl;
      }

      // Add optional no_cache and async if provided
      if (propsValue.no_cache) {
        (searchConfig as any).no_cache = propsValue.no_cache;
      }

      if (propsValue.async) {
        (searchConfig as any).async = propsValue.async;
      }

      // Execute search with comprehensive error handling
      const response = await client.executeSearch(searchConfig, {
        timeout: 30000,
        retries: 3,
        retryDelay: 1000,
      });

      // Return structured response with metadata
      return {
        success: true,
        ...response,
      };
    } catch (error: unknown) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';

      return {
        success: false,
        error: errorMessage,
        error_type: error instanceof Error ? error.constructor.name : 'UnknownError',
        timestamp: new Date().toISOString(),
        search_query: propsValue.query,
      };
    }
  },
});
