import { logger } from '../../utils/logger';
import axios from 'axios';

interface GoogleAdsCampaign {
  campaignId: string;
  name: string;
  type: 'SEARCH' | 'DISPLAY' | 'SHOPPING' | 'VIDEO' | 'PERFORMANCE_MAX';
  status: 'DRAFT' | 'ENABLED' | 'PAUSED' | 'REMOVED';
  budget: {
    amountMicros: number;
    currency: string;
  };
  networkSettings: {
    targetGoogleSearch: boolean;
    targetSearchNetwork: boolean;
    targetContentNetwork: boolean;
    targetPartnerSearchNetwork: boolean;
  };
  biddingStrategy: 'MANUAL_CPC' | 'MANUAL_CPM' | 'TARGET_SPEND' | 'TARGET_CPA' | 'TARGET_ROAS';
}

interface GoogleAdsAdGroup {
  adGroupId: string;
  campaignId: string;
  name: string;
  status: 'DRAFT' | 'ENABLED' | 'PAUSED';
  type: 'SEARCH_STANDARD' | 'DISPLAY_STANDARD' | 'SHOPPING_PRODUCT_ADS';
  cpcBidMicros?: number;
  cpmBidMicros?: number;
}

interface GoogleAdsAd {
  adId: string;
  adGroupId: string;
  type: 'TEXT_AD' | 'IMAGE_AD' | 'VIDEO_AD' | 'SHOPPING_AD' | 'RESPONSIVE_SEARCH_AD';
  status: 'DRAFT' | 'ENABLED' | 'PAUSED';
  content: {
    headline?: string[];
    description?: string[];
    finalUrl?: string;
    displayUrl?: string;
    imageUrl?: string;
    videoUrl?: string;
  };
}

interface GoogleAdsPerformance {
  campaignId: string;
  adGroupId?: string;
  adId?: string;
  dateRange: {
    start: string;
    end: string;
  };
  metrics: {
    impressions: number;
    clicks: number;
    ctr: number;
    averageCpc: number;
    averageCpm: number;
    costMicros: number;
    conversions: number;
    conversionRate: number;
    costPerConversion: number;
    roas: number;
    allConversionsValue: number;
  };
}

interface GoogleAdsKeyword {
  keywordId: string;
  adGroupId: string;
  text: string;
  matchType: 'EXACT' | 'PHRASE' | 'BROAD';
  status: 'ENABLED' | 'PAUSED';
  cpcBidMicros: number;
  qualityScore?: number;
}

export class GoogleAdsConnector {
  platformCode = 'GOOGLE_ADS';
  capabilities = {
    hasApi: true,
    supportsCampaignCreate: true,
    supportsAdCreate: true,
    supportsPerformanceReport: true,
    supportsKeywordManagement: true,
    supportsShoppingAds: true
  };

  private apiBaseUrl = 'https://googleads.googleapis.com/v15';
  private developerToken = process.env.GOOGLE_ADS_DEVELOPER_TOKEN || '';
  private clientId = process.env.GOOGLE_ADS_CLIENT_ID || '';
  private clientSecret = process.env.GOOGLE_ADS_CLIENT_SECRET || '';
  private refreshToken = process.env.GOOGLE_ADS_REFRESH_TOKEN || '';
  private customerId = process.env.GOOGLE_ADS_CUSTOMER_ID || '';

  async authorize(customerId: string): Promise<boolean> {
    logger.info(`[GoogleAdsConnector] Authorizing customer: ${customerId}`);
    
    if (!this.developerToken || this.developerToken === '') {
      logger.warn('[GoogleAdsConnector] No API credentials configured, using mock mode');
      return true;
    }

    try {
      const response = await axios.get(
        `${this.apiBaseUrl}/customers/${customerId}/googleAds:search`,
        {
          params: { query: 'SELECT customer.id FROM customer LIMIT 1' },
          headers: {
            'developer-token': this.developerToken,
            'Authorization': `Bearer ${this.refreshToken}`
          }
        }
      );
      return response.status === 200;
    } catch (error: any) {
      logger.error(`[GoogleAdsConnector] Authorization failed: ${error.message}`);
      return false;
    }
  }

  async createCampaign(customerId: string, campaign: Partial<GoogleAdsCampaign>): Promise<GoogleAdsCampaign> {
    logger.info(`[GoogleAdsConnector] Creating campaign: ${campaign.name}`);

    if (!this.developerToken || this.developerToken === '') {
      return this.getMockCampaign(campaign);
    }

    try {
      const campaignTypeMap: Record<string, string> = {
        'SEARCH': 'SEARCH',
        'DISPLAY': 'DISPLAY',
        'SHOPPING': 'SHOPPING',
        'VIDEO': 'VIDEO',
        'PERFORMANCE_MAX': 'PERFORMANCE_MAX'
      };

      const response = await axios.post(
        `${this.apiBaseUrl}/customers/${customerId}/campaigns:mutate`,
        {
          operations: [{
            create: {
              name: campaign.name,
              advertising_channel_type: campaignTypeMap[campaign.type || 'SEARCH'],
              status: 'PAUSED',
              campaign_budget: `customers/${customerId}/campaignBudgets/${Date.now()}`,
              network_settings: {
                target_google_search: campaign.networkSettings?.targetGoogleSearch ?? true,
                target_search_network: campaign.networkSettings?.targetSearchNetwork ?? true,
                target_content_network: campaign.networkSettings?.targetContentNetwork ?? false
              },
              bidding_strategy_type: campaign.biddingStrategy || 'MANUAL_CPC'
            }
          }]
        },
        {
          headers: {
            'developer-token': this.developerToken,
            'Authorization': `Bearer ${this.refreshToken}`
          }
        }
      );

      return {
        campaignId: response.data?.results?.[0]?.resourceName?.split('/').pop(),
        name: campaign.name || '',
        type: campaign.type || 'SEARCH',
        status: 'DRAFT',
        budget: campaign.budget || { amountMicros: 0, currency: 'USD' },
        networkSettings: campaign.networkSettings || {
          targetGoogleSearch: true,
          targetSearchNetwork: true,
          targetContentNetwork: false,
          targetPartnerSearchNetwork: false
        },
        biddingStrategy: campaign.biddingStrategy || 'MANUAL_CPC'
      };
    } catch (error: any) {
      logger.error(`[GoogleAdsConnector] Create campaign failed: ${error.message}`);
      throw error;
    }
  }

  async createAdGroup(customerId: string, adGroup: Partial<GoogleAdsAdGroup>): Promise<GoogleAdsAdGroup> {
    logger.info(`[GoogleAdsConnector] Creating ad group: ${adGroup.name}`);

    if (!this.developerToken || this.developerToken === '') {
      return this.getMockAdGroup(adGroup);
    }

    try {
      const response = await axios.post(
        `${this.apiBaseUrl}/customers/${customerId}/adGroups:mutate`,
        {
          operations: [{
            create: {
              name: adGroup.name,
              campaign: `customers/${customerId}/campaigns/${adGroup.campaignId}`,
              status: 'PAUSED',
              type: adGroup.type || 'SEARCH_STANDARD',
              cpc_bid_micros: adGroup.cpcBidMicros || 1000000
            }
          }]
        },
        {
          headers: {
            'developer-token': this.developerToken,
            'Authorization': `Bearer ${this.refreshToken}`
          }
        }
      );

      return {
        adGroupId: response.data?.results?.[0]?.resourceName?.split('/').pop(),
        campaignId: adGroup.campaignId || '',
        name: adGroup.name || '',
        status: 'DRAFT',
        type: adGroup.type || 'SEARCH_STANDARD',
        cpcBidMicros: adGroup.cpcBidMicros
      };
    } catch (error: any) {
      logger.error(`[GoogleAdsConnector] Create ad group failed: ${error.message}`);
      throw error;
    }
  }

  async createAd(customerId: string, ad: Partial<GoogleAdsAd>): Promise<GoogleAdsAd> {
    logger.info(`[GoogleAdsConnector] Creating ad: ${ad.type}`);

    if (!this.developerToken || this.developerToken === '') {
      return this.getMockAd(ad);
    }

    try {
      let adData: any = {};

      if (ad.type === 'RESPONSIVE_SEARCH_AD') {
        adData = {
          responsive_search_ad: {
            headlines: ad.content?.headline?.map(text => ({ text })) || [],
            descriptions: ad.content?.description?.map(text => ({ text })) || [],
            final_urls: ad.content?.finalUrl ? [ad.content.finalUrl] : []
          }
        };
      } else if (ad.type === 'TEXT_AD') {
        adData = {
          text_ad: {
            headline: ad.content?.headline?.[0] || '',
            description1: ad.content?.description?.[0] || '',
            description2: ad.content?.description?.[1] || '',
            final_urls: ad.content?.finalUrl ? [ad.content.finalUrl] : []
          }
        };
      }

      const response = await axios.post(
        `${this.apiBaseUrl}/customers/${customerId}/ads:mutate`,
        {
          operations: [{
            create: {
              ad_group: `customers/${customerId}/adGroups/${ad.adGroupId}`,
              status: 'PAUSED',
              ...adData
            }
          }]
        },
        {
          headers: {
            'developer-token': this.developerToken,
            'Authorization': `Bearer ${this.refreshToken}`
          }
        }
      );

      return {
        adId: response.data?.results?.[0]?.resourceName?.split('/').pop(),
        adGroupId: ad.adGroupId || '',
        type: ad.type || 'TEXT_AD',
        status: 'DRAFT',
        content: ad.content || {}
      };
    } catch (error: any) {
      logger.error(`[GoogleAdsConnector] Create ad failed: ${error.message}`);
      throw error;
    }
  }

  async addKeywords(customerId: string, adGroupId: string, keywords: Array<{
    text: string;
    matchType: 'EXACT' | 'PHRASE' | 'BROAD';
    cpcBidMicros: number;
  }>): Promise<GoogleAdsKeyword[]> {
    logger.info(`[GoogleAdsConnector] Adding ${keywords.length} keywords to ad group: ${adGroupId}`);

    if (!this.developerToken || this.developerToken === '') {
      return keywords.map((kw, i) => ({
        keywordId: `KW_${Date.now()}_${i}`,
        adGroupId,
        text: kw.text,
        matchType: kw.matchType,
        status: 'ENABLED',
        cpcBidMicros: kw.cpcBidMicros
      }));
    }

    try {
      const response = await axios.post(
        `${this.apiBaseUrl}/customers/${customerId}/adGroupCriteria:mutate`,
        {
          operations: keywords.map(kw => ({
            create: {
              ad_group: `customers/${customerId}/adGroups/${adGroupId}`,
              keyword: {
                text: kw.text,
                match_type: kw.matchType
              },
              cpc_bid_micros: kw.cpcBidMicros
            }
          }))
        },
        {
          headers: {
            'developer-token': this.developerToken,
            'Authorization': `Bearer ${this.refreshToken}`
          }
        }
      );

      return (response.data?.results || []).map((result: any, i: number) => ({
        keywordId: result.resourceName?.split('/').pop(),
        adGroupId,
        text: keywords[i].text,
        matchType: keywords[i].matchType,
        status: 'ENABLED',
        cpcBidMicros: keywords[i].cpcBidMicros
      }));
    } catch (error: any) {
      logger.error(`[GoogleAdsConnector] Add keywords failed: ${error.message}`);
      throw error;
    }
  }

  async getPerformance(customerId: string, params: {
    campaignIds?: string[];
    adGroupIds?: string[];
    adIds?: string[];
    startDate: string;
    endDate: string;
  }): Promise<GoogleAdsPerformance[]> {
    logger.info(`[GoogleAdsConnector] Getting performance for customer: ${customerId}`);

    if (!this.developerToken || this.developerToken === '') {
      return this.getMockPerformance(params);
    }

    try {
      const metrics = 'metrics.impressions,metrics.clicks,metrics.ctr,metrics.average_cpc,metrics.average_cpm,metrics.cost_micros,metrics.conversions,metrics.conversions_from_interactions_rate,metrics.cost_per_conversion,metrics.all_conversions_value';
      const segments = 'segments.date';
      
      let query = `SELECT campaign.id, ad_group.id, ad_group_ad.ad.id, ${metrics} FROM ad_group_ad WHERE segments.date BETWEEN '${params.startDate}' AND '${params.endDate}'`;
      
      if (params.campaignIds?.length) {
        query += ` AND campaign.id IN (${params.campaignIds.map(id => `'${id}'`).join(',')})`;
      }

      const response = await axios.post(
        `${this.apiBaseUrl}/customers/${customerId}/googleAds:search`,
        { query },
        {
          headers: {
            'developer-token': this.developerToken,
            'Authorization': `Bearer ${this.refreshToken}`
          }
        }
      );

      return (response.data?.results || []).map((item: any) => ({
        campaignId: item.campaign?.id,
        adGroupId: item.adGroup?.id,
        adId: item.adGroupAd?.ad?.id,
        dateRange: { start: params.startDate, end: params.endDate },
        metrics: {
          impressions: parseInt(item.metrics?.impressions) || 0,
          clicks: parseInt(item.metrics?.clicks) || 0,
          ctr: parseFloat(item.metrics?.ctr) || 0,
          averageCpc: parseInt(item.metrics?.averageCpc) || 0,
          averageCpm: parseInt(item.metrics?.averageCpm) || 0,
          costMicros: parseInt(item.metrics?.costMicros) || 0,
          conversions: parseFloat(item.metrics?.conversions) || 0,
          conversionRate: parseFloat(item.metrics?.conversionsFromInteractionsRate) || 0,
          costPerConversion: parseInt(item.metrics?.costPerConversion) || 0,
          roas: item.metrics?.costPerConversion ? 
            (parseFloat(item.metrics?.allConversionsValue) / (parseInt(item.metrics?.costMicros) / 1000000)) : 0,
          allConversionsValue: parseFloat(item.metrics?.allConversionsValue) || 0
        }
      }));
    } catch (error: any) {
      logger.error(`[GoogleAdsConnector] Get performance failed: ${error.message}`);
      return this.getMockPerformance(params);
    }
  }

  async updateCampaignStatus(campaignId: string, status: 'ENABLED' | 'PAUSED'): Promise<boolean> {
    logger.info(`[GoogleAdsConnector] Updating campaign ${campaignId} status to ${status}`);
    
    if (!this.developerToken || this.developerToken === '') {
      return true;
    }

    try {
      await axios.post(
        `${this.apiBaseUrl}/customers/${this.customerId}/campaigns:mutate`,
        {
          operations: [{
            update: {
              resource_name: `customers/${this.customerId}/campaigns/${campaignId}`,
              status
            },
            update_mask: 'status'
          }]
        },
        {
          headers: {
            'developer-token': this.developerToken,
            'Authorization': `Bearer ${this.refreshToken}`
          }
        }
      );
      return true;
    } catch (error: any) {
      logger.error(`[GoogleAdsConnector] Update campaign status failed: ${error.message}`);
      return false;
    }
  }

  async getCampaigns(customerId: string): Promise<GoogleAdsCampaign[]> {
    logger.info(`[GoogleAdsConnector] Getting campaigns for customer: ${customerId}`);
    
    if (!this.developerToken || this.developerToken === '') {
      return [
        {
          campaignId: 'GOOG_CAMP_001',
          name: 'Search Campaign - Electronics',
          type: 'SEARCH',
          status: 'ENABLED',
          budget: { amountMicros: 50000000, currency: 'USD' },
          networkSettings: {
            targetGoogleSearch: true,
            targetSearchNetwork: true,
            targetContentNetwork: false,
            targetPartnerSearchNetwork: false
          },
          biddingStrategy: 'TARGET_SPEND'
        },
        {
          campaignId: 'GOOG_CAMP_002',
          name: 'Shopping Campaign - Products',
          type: 'SHOPPING',
          status: 'ENABLED',
          budget: { amountMicros: 100000000, currency: 'USD' },
          networkSettings: {
            targetGoogleSearch: true,
            targetSearchNetwork: false,
            targetContentNetwork: false,
            targetPartnerSearchNetwork: false
          },
          biddingStrategy: 'TARGET_ROAS'
        }
      ];
    }

    try {
      const query = `SELECT campaign.id, campaign.name, campaign.advertising_channel_type, campaign.status, campaign_budget.amount_micros FROM campaign WHERE campaign.status != 'REMOVED'`;
      
      const response = await axios.post(
        `${this.apiBaseUrl}/customers/${customerId}/googleAds:search`,
        { query },
        {
          headers: {
            'developer-token': this.developerToken,
            'Authorization': `Bearer ${this.refreshToken}`
          }
        }
      );

      return (response.data?.results || []).map((item: any) => ({
        campaignId: item.campaign?.id,
        name: item.campaign?.name,
        type: item.campaign?.advertisingChannelType as any,
        status: item.campaign?.status as any,
        budget: {
          amountMicros: parseInt(item.campaignBudget?.amountMicros) || 0,
          currency: 'USD'
        },
        networkSettings: {
          targetGoogleSearch: true,
          targetSearchNetwork: true,
          targetContentNetwork: false,
          targetPartnerSearchNetwork: false
        },
        biddingStrategy: 'MANUAL_CPC'
      }));
    } catch (error: any) {
      logger.error(`[GoogleAdsConnector] Get campaigns failed: ${error.message}`);
      return [];
    }
  }

  private getMockCampaign(campaign: Partial<GoogleAdsCampaign>): GoogleAdsCampaign {
    return {
      campaignId: `GOOG_CAMP_${Date.now()}`,
      name: campaign.name || 'New Campaign',
      type: campaign.type || 'SEARCH',
      status: 'DRAFT',
      budget: campaign.budget || { amountMicros: 50000000, currency: 'USD' },
      networkSettings: campaign.networkSettings || {
        targetGoogleSearch: true,
        targetSearchNetwork: true,
        targetContentNetwork: false,
        targetPartnerSearchNetwork: false
      },
      biddingStrategy: campaign.biddingStrategy || 'MANUAL_CPC'
    };
  }

  private getMockAdGroup(adGroup: Partial<GoogleAdsAdGroup>): GoogleAdsAdGroup {
    return {
      adGroupId: `GOOG_AG_${Date.now()}`,
      campaignId: adGroup.campaignId || '',
      name: adGroup.name || 'New Ad Group',
      status: 'DRAFT',
      type: adGroup.type || 'SEARCH_STANDARD',
      cpcBidMicros: adGroup.cpcBidMicros || 1000000
    };
  }

  private getMockAd(ad: Partial<GoogleAdsAd>): GoogleAdsAd {
    return {
      adId: `GOOG_AD_${Date.now()}`,
      adGroupId: ad.adGroupId || '',
      type: ad.type || 'RESPONSIVE_SEARCH_AD',
      status: 'DRAFT',
      content: ad.content || {
        headline: ['Shop Now', 'Best Deals'],
        description: ['Find the best products here.', 'Free shipping on all orders.'],
        finalUrl: 'https://example.com/shop'
      }
    };
  }

  private getMockPerformance(params: { startDate: string; endDate: string; campaignIds?: string[] }): GoogleAdsPerformance[] {
    const campaignIds = params.campaignIds || ['GOOG_CAMP_001', 'GOOG_CAMP_002'];
    
    return campaignIds.map(campaignId => ({
      campaignId,
      dateRange: { start: params.startDate, end: params.endDate },
      metrics: {
        impressions: Math.floor(Math.random() * 200000) + 30000,
        clicks: Math.floor(Math.random() * 10000) + 1000,
        ctr: Math.random() * 5 + 1,
        averageCpc: Math.floor(Math.random() * 2000000) + 500000,
        averageCpm: Math.floor(Math.random() * 10000000) + 2000000,
        costMicros: Math.floor(Math.random() * 1000000000) + 100000000,
        conversions: Math.floor(Math.random() * 200) + 20,
        conversionRate: Math.random() * 5 + 0.5,
        costPerConversion: Math.floor(Math.random() * 50000000) + 10000000,
        roas: Math.random() * 8 + 1,
        allConversionsValue: Math.random() * 50000 + 5000
      }
    }));
  }
}

export default GoogleAdsConnector;
