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

interface FacebookAdCampaign {
  campaignId: string;
  name: string;
  objective: 'AWARENESS' | 'TRAFFIC' | 'ENGAGEMENT' | 'LEADS' | 'APP_PROMOTION' | 'SALES';
  status: 'DRAFT' | 'ACTIVE' | 'PAUSED' | 'ARCHIVED';
  budget: {
    daily?: number;
    lifetime?: number;
    currency: string;
  };
  specialCategories?: string[];
}

interface FacebookAdSet {
  adSetId: string;
  campaignId: string;
  name: string;
  status: 'DRAFT' | 'ACTIVE' | 'PAUSED';
  targeting: {
    ageMin?: number;
    ageMax?: number;
    genders?: ('male' | 'female')[];
    locations?: {
      countries?: string[];
      regions?: string[];
      cities?: string[];
    };
    interests?: string[];
    behaviors?: string[];
    customAudiences?: string[];
    lookalikeAudiences?: string[];
  };
  budget: {
    daily?: number;
    lifetime?: number;
    currency: string;
  };
  bidStrategy: 'LOWEST_COST_WITHOUT_CAP' | 'LOWEST_COST_WITH_BID_CAP' | 'TARGET_COST';
  bidAmount?: number;
  optimizationGoal: 'REACH' | 'IMPRESSIONS' | 'LINK_CLICKS' | 'CONVERSIONS' | 'VALUE';
}

interface FacebookAd {
  adId: string;
  adSetId: string;
  name: string;
  status: 'DRAFT' | 'ACTIVE' | 'PAUSED' | 'REJECTED';
  creative: {
    type: 'IMAGE' | 'VIDEO' | 'CAROUSEL' | 'COLLECTION';
    mediaUrl: string;
    thumbnailUrl?: string;
    headline: string;
    description?: string;
    callToAction: string;
    landingPageUrl: string;
    linkCaption?: string;
  };
}

interface FacebookAdPerformance {
  adId: string;
  dateRange: {
    start: string;
    end: string;
  };
  metrics: {
    impressions: number;
    reach: number;
    frequency: number;
    clicks: number;
    uniqueClicks: number;
    ctr: number;
    spend: number;
    cpc: number;
    cpm: number;
    conversions: number;
    conversionRate: number;
    costPerConversion: number;
    roas: number;
    purchaseValue: number;
  };
}

export class FacebookAdsConnector {
  platformCode = 'FACEBOOK_ADS';
  capabilities = {
    hasApi: true,
    supportsCampaignCreate: true,
    supportsAdCreate: true,
    supportsPerformanceReport: true,
    supportsAudienceTargeting: true,
    supportsLookalikeAudiences: true
  };

  private apiBaseUrl = 'https://graph.facebook.com/v18.0';
  private appId = process.env.FACEBOOK_APP_ID || '';
  private appSecret = process.env.FACEBOOK_APP_SECRET || '';
  private accessToken = process.env.FACEBOOK_ACCESS_TOKEN || '';

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

    try {
      const response = await axios.get(`${this.apiBaseUrl}/${adAccountId}`, {
        params: {
          fields: 'id,name,account_status',
          access_token: this.accessToken
        }
      });
      return response.data?.account_status === 1;
    } catch (error: any) {
      logger.error(`[FacebookAdsConnector] Authorization failed: ${error.message}`);
      return false;
    }
  }

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

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

    try {
      const objectiveMap: Record<string, string> = {
        'AWARENESS': 'OUTCOME_AWARENESS',
        'TRAFFIC': 'OUTCOME_TRAFFIC',
        'ENGAGEMENT': 'OUTCOME_ENGAGEMENT',
        'LEADS': 'OUTCOME_LEADS',
        'APP_PROMOTION': 'OUTCOME_APP_PROMOTION',
        'SALES': 'OUTCOME_SALES'
      };

      const response = await axios.post(
        `${this.apiBaseUrl}/${adAccountId}/campaigns`,
        {
          name: campaign.name,
          objective: objectiveMap[campaign.objective || 'SALES'],
          status: 'PAUSED',
          special_ad_categories: campaign.specialCategories || [],
          daily_budget: campaign.budget?.daily ? Math.round(campaign.budget.daily * 100) : undefined,
          lifetime_budget: campaign.budget?.lifetime ? Math.round(campaign.budget.lifetime * 100) : undefined
        },
        { params: { access_token: this.accessToken } }
      );

      return {
        campaignId: response.data?.id,
        name: campaign.name || '',
        objective: campaign.objective || 'SALES',
        status: 'DRAFT',
        budget: campaign.budget || { currency: 'USD' },
        specialCategories: campaign.specialCategories
      };
    } catch (error: any) {
      logger.error(`[FacebookAdsConnector] Create campaign failed: ${error.message}`);
      throw error;
    }
  }

  async createAdSet(adAccountId: string, adSet: Partial<FacebookAdSet>): Promise<FacebookAdSet> {
    logger.info(`[FacebookAdsConnector] Creating ad set: ${adSet.name}`);

    if (!this.appId || this.appId === '') {
      return this.getMockAdSet(adSet);
    }

    try {
      const targeting: any = {};
      
      if (adSet.targeting?.ageMin || adSet.targeting?.ageMax) {
        targeting.age_min = adSet.targeting.ageMin || 18;
        targeting.age_max = adSet.targeting.ageMax || 65;
      }
      
      if (adSet.targeting?.genders) {
        targeting.genders = adSet.targeting.genders.map(g => g === 'male' ? 1 : 2);
      }
      
      if (adSet.targeting?.locations?.countries) {
        targeting.geo_locations = { countries: adSet.targeting.locations.countries };
      }
      
      if (adSet.targeting?.interests) {
        targeting.interests = adSet.targeting.interests.map(id => ({ id, name: id }));
      }

      const response = await axios.post(
        `${this.apiBaseUrl}/${adAccountId}/adsets`,
        {
          name: adSet.name,
          campaign_id: adSet.campaignId,
          status: 'PAUSED',
          targeting,
          daily_budget: adSet.budget?.daily ? Math.round(adSet.budget.daily * 100) : undefined,
          lifetime_budget: adSet.budget?.lifetime ? Math.round(adSet.budget.lifetime * 100) : undefined,
          bid_strategy: adSet.bidStrategy || 'LOWEST_COST_WITHOUT_CAP',
          optimization_goal: adSet.optimizationGoal || 'CONVERSIONS',
          billing_event: 'IMPRESSIONS'
        },
        { params: { access_token: this.accessToken } }
      );

      return {
        adSetId: response.data?.id,
        campaignId: adSet.campaignId || '',
        name: adSet.name || '',
        status: 'DRAFT',
        targeting: adSet.targeting || {},
        budget: adSet.budget || { currency: 'USD' },
        bidStrategy: adSet.bidStrategy || 'LOWEST_COST_WITHOUT_CAP',
        optimizationGoal: adSet.optimizationGoal || 'CONVERSIONS'
      };
    } catch (error: any) {
      logger.error(`[FacebookAdsConnector] Create ad set failed: ${error.message}`);
      throw error;
    }
  }

  async createAd(adAccountId: string, ad: Partial<FacebookAd>): Promise<FacebookAd> {
    logger.info(`[FacebookAdsConnector] Creating ad: ${ad.name}`);

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

    try {
      const creativeData: any = {
        name: ad.name,
        object_story_spec: {
          link_data: {
            link: ad.creative?.landingPageUrl,
            message: ad.creative?.description || '',
            name: ad.creative?.headline,
            call_to_action: { type: ad.creative?.callToAction || 'SHOP_NOW' },
            image_hash: ad.creative?.mediaUrl
          },
          page_id: adAccountId
        }
      };

      const creativeResponse = await axios.post(
        `${this.apiBaseUrl}/${adAccountId}/adcreatives`,
        creativeData,
        { params: { access_token: this.accessToken } }
      );

      const response = await axios.post(
        `${this.apiBaseUrl}/${adAccountId}/ads`,
        {
          name: ad.name,
          adset_id: ad.adSetId,
          creative: { creative_id: creativeResponse.data?.id },
          status: 'PAUSED'
        },
        { params: { access_token: this.accessToken } }
      );

      return {
        adId: response.data?.id,
        adSetId: ad.adSetId || '',
        name: ad.name || '',
        status: 'DRAFT',
        creative: ad.creative || {
          type: 'IMAGE',
          mediaUrl: '',
          headline: '',
          callToAction: 'SHOP_NOW',
          landingPageUrl: ''
        }
      };
    } catch (error: any) {
      logger.error(`[FacebookAdsConnector] Create ad failed: ${error.message}`);
      throw error;
    }
  }

  async getPerformance(adAccountId: string, params: {
    adIds?: string[];
    campaignIds?: string[];
    startDate: string;
    endDate: string;
  }): Promise<FacebookAdPerformance[]> {
    logger.info(`[FacebookAdsConnector] Getting performance for ad account: ${adAccountId}`);

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

    try {
      const insightsParams: any = {
        level: 'ad',
        date_range: {
          since: params.startDate,
          until: params.endDate
        },
        fields: 'ad_id,impressions,reach,frequency,clicks,unique_clicks,spend,cpc,cpm,conversions,purchase_roas,action_values',
        access_token: this.accessToken
      };

      if (params.adIds?.length) {
        insightsParams.filtering = [{ field: 'ad.id', operator: 'IN', value: params.adIds }];
      }

      const response = await axios.get(
        `${this.apiBaseUrl}/${adAccountId}/insights`,
        { params: insightsParams }
      );

      return (response.data?.data || []).map((item: any) => ({
        adId: item.ad_id,
        dateRange: { start: params.startDate, end: params.endDate },
        metrics: {
          impressions: parseInt(item.impressions) || 0,
          reach: parseInt(item.reach) || 0,
          frequency: parseFloat(item.frequency) || 0,
          clicks: parseInt(item.clicks) || 0,
          uniqueClicks: parseInt(item.unique_clicks) || 0,
          ctr: parseFloat(item.ctr) || 0,
          spend: parseFloat(item.spend) || 0,
          cpc: parseFloat(item.cpc) || 0,
          cpm: parseFloat(item.cpm) || 0,
          conversions: parseInt(item.conversions) || 0,
          conversionRate: item.clicks ? (parseInt(item.conversions) / parseInt(item.clicks)) * 100 : 0,
          costPerConversion: item.conversions ? parseFloat(item.spend) / parseInt(item.conversions) : 0,
          roas: parseFloat(item.purchase_roas?.[0]?.value) || 0,
          purchaseValue: parseFloat(item.action_values?.find((a: any) => a.action_type === 'omni_purchase')?.value) || 0
        }
      }));
    } catch (error: any) {
      logger.error(`[FacebookAdsConnector] Get performance failed: ${error.message}`);
      return this.getMockPerformance(params);
    }
  }

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

    try {
      await axios.post(
        `${this.apiBaseUrl}/${campaignId}`,
        { status: status === 'ACTIVE' ? 'ACTIVE' : 'PAUSED' },
        { params: { access_token: this.accessToken } }
      );
      return true;
    } catch (error: any) {
      logger.error(`[FacebookAdsConnector] Update campaign status failed: ${error.message}`);
      return false;
    }
  }

  async getCampaigns(adAccountId: string): Promise<FacebookAdCampaign[]> {
    logger.info(`[FacebookAdsConnector] Getting campaigns for ad account: ${adAccountId}`);
    
    if (!this.appId || this.appId === '') {
      return [
        {
          campaignId: 'FB_CAMP_001',
          name: 'Holiday Sales Campaign',
          objective: 'SALES',
          status: 'ACTIVE',
          budget: { daily: 100, currency: 'USD' }
        },
        {
          campaignId: 'FB_CAMP_002',
          name: 'Brand Awareness Q1',
          objective: 'AWARENESS',
          status: 'PAUSED',
          budget: { lifetime: 5000, currency: 'USD' }
        }
      ];
    }

    try {
      const response = await axios.get(`${this.apiBaseUrl}/${adAccountId}/campaigns`, {
        params: {
          fields: 'id,name,objective,status,daily_budget,lifetime_budget',
          access_token: this.accessToken
        }
      });
      
      return (response.data?.data || []).map((item: any) => ({
        campaignId: item.id,
        name: item.name,
        objective: item.objective?.replace('OUTCOME_', '') as any,
        status: item.status,
        budget: {
          daily: item.daily_budget ? parseInt(item.daily_budget) / 100 : undefined,
          lifetime: item.lifetime_budget ? parseInt(item.lifetime_budget) / 100 : undefined,
          currency: 'USD'
        }
      }));
    } catch (error: any) {
      logger.error(`[FacebookAdsConnector] Get campaigns failed: ${error.message}`);
      return [];
    }
  }

  async createLookalikeAudience(adAccountId: string, params: {
    name: string;
    sourceAudienceId: string;
    country: string;
    ratio: number;
  }): Promise<{ audienceId: string; name: string }> {
    logger.info(`[FacebookAdsConnector] Creating lookalike audience: ${params.name}`);

    if (!this.appId || this.appId === '') {
      return {
        audienceId: `FB_LAL_${Date.now()}`,
        name: params.name
      };
    }

    try {
      const response = await axios.post(
        `${this.apiBaseUrl}/${adAccountId}/customaudiences`,
        {
          name: params.name,
          subtype: 'LOOKALIKE',
          lookalike_spec: JSON.stringify({
            origin_audience_id: params.sourceAudienceId,
            country: params.country,
            starting_ratio: params.ratio * 0.01,
            ratio: params.ratio * 0.01 + 0.01
          })
        },
        { params: { access_token: this.accessToken } }
      );

      return {
        audienceId: response.data?.id,
        name: params.name
      };
    } catch (error: any) {
      logger.error(`[FacebookAdsConnector] Create lookalike audience failed: ${error.message}`);
      throw error;
    }
  }

  private getMockCampaign(campaign: Partial<FacebookAdCampaign>): FacebookAdCampaign {
    return {
      campaignId: `FB_CAMP_${Date.now()}`,
      name: campaign.name || 'New Campaign',
      objective: campaign.objective || 'SALES',
      status: 'DRAFT',
      budget: campaign.budget || { daily: 50, currency: 'USD' },
      specialCategories: campaign.specialCategories
    };
  }

  private getMockAdSet(adSet: Partial<FacebookAdSet>): FacebookAdSet {
    return {
      adSetId: `FB_AS_${Date.now()}`,
      campaignId: adSet.campaignId || '',
      name: adSet.name || 'New Ad Set',
      status: 'DRAFT',
      targeting: adSet.targeting || { ageMin: 18, ageMax: 65, locations: { countries: ['US'] } },
      budget: adSet.budget || { daily: 20, currency: 'USD' },
      bidStrategy: adSet.bidStrategy || 'LOWEST_COST_WITHOUT_CAP',
      optimizationGoal: adSet.optimizationGoal || 'CONVERSIONS'
    };
  }

  private getMockAd(ad: Partial<FacebookAd>): FacebookAd {
    return {
      adId: `FB_AD_${Date.now()}`,
      adSetId: ad.adSetId || '',
      name: ad.name || 'New Ad',
      status: 'DRAFT',
      creative: ad.creative || {
        type: 'IMAGE',
        mediaUrl: 'https://example.com/image.jpg',
        headline: 'Shop Now',
        callToAction: 'SHOP_NOW',
        landingPageUrl: 'https://example.com/shop'
      }
    };
  }

  private getMockPerformance(params: { startDate: string; endDate: string; adIds?: string[] }): FacebookAdPerformance[] {
    const adIds = params.adIds || ['FB_AD_001', 'FB_AD_002'];
    
    return adIds.map(adId => ({
      adId,
      dateRange: { start: params.startDate, end: params.endDate },
      metrics: {
        impressions: Math.floor(Math.random() * 150000) + 20000,
        reach: Math.floor(Math.random() * 100000) + 15000,
        frequency: Math.random() * 3 + 1,
        clicks: Math.floor(Math.random() * 8000) + 800,
        uniqueClicks: Math.floor(Math.random() * 6000) + 600,
        ctr: Math.random() * 4 + 0.5,
        spend: Math.random() * 800 + 100,
        cpc: Math.random() * 1.5 + 0.3,
        cpm: Math.random() * 15 + 3,
        conversions: Math.floor(Math.random() * 150) + 15,
        conversionRate: Math.random() * 4 + 0.5,
        costPerConversion: Math.random() * 25 + 5,
        roas: Math.random() * 6 + 1,
        purchaseValue: Math.random() * 3000 + 500
      }
    }));
  }
}

export default FacebookAdsConnector;
