import { CatalogProductRecord } from '@/types';
import { logger } from '@/lib/logger';
import { META_CONFIG } from '@/config/meta';

interface MetaCatalogBatchRequest {
  method: 'CREATE' | 'UPDATE' | 'DELETE';
  retailer_id: string;
  data?: Record<string, unknown>;
}

export interface MetaUserProfile {
  id: string;
  name: string;
  email?: string;
  avatar?: string | null;
}

export class MetaGraphClient {
  private accessToken: string;
  private version: string;

  constructor(accessToken: string) {
    this.accessToken = accessToken;
    this.version = META_CONFIG.graphVersion;
  }

  /**
   * Fetches the authenticated Meta User Profile.
   */
  async getUserProfile(): Promise<MetaUserProfile | null> {
    if (!this.accessToken) return null;
    const url = `https://graph.facebook.com/${this.version}/me?fields=id,name,email,picture.type(large)&access_token=${encodeURIComponent(this.accessToken)}`;
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(6000) });
      const data = await res.json();
      if (data.error || !data.id) {
        logger.warn('Meta getUserProfile failed', { error: String(data.error?.message || data.error) });
        return null;
      }
      return {
        id: data.id,
        name: data.name || 'Meta User',
        email: data.email || undefined,
        avatar: data.picture?.data?.url || `https://graph.facebook.com/${data.id}/picture?type=large`,
      };
    } catch (err) {
      logger.error('Failed to fetch Meta user profile', err);
      return null;
    }
  }

  /**
   * Fetches Business Managers accessible by the authenticated Meta user.
   */
  async getBusinesses(): Promise<Array<{ id: string; name: string }>> {
    if (!this.accessToken) return [];
    const url = `https://graph.facebook.com/${this.version}/me/businesses?fields=id,name,verification_status&access_token=${encodeURIComponent(this.accessToken)}`;
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(2000) });
      const data = await res.json();
      if (data.error || !Array.isArray(data.data)) {
        logger.warn('Meta getBusinesses failed', { error: String(data.error?.message || data.error) });
        return [];
      }
      return data.data.map((b: { id: string; name: string }) => ({
        id: b.id,
        name: b.name ? `${b.name} (${b.id})` : b.id,
      }));
    } catch (err) {
      logger.error('Failed to fetch Meta businesses', err);
      return [];
    }
  }

  /**
   * Fetches Product Catalogs under a Meta Business.
   */
  async getCatalogs(businessId: string): Promise<Array<{ id: string; name: string; product_count?: number }>> {
    if (!this.accessToken || !businessId) return [];
    const url = `https://graph.facebook.com/${this.version}/${businessId}/owned_product_catalogs?fields=id,name,product_count&access_token=${encodeURIComponent(this.accessToken)}`;
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(2000) });
      const data = await res.json();
      if (data.error || !Array.isArray(data.data)) {
        return [];
      }
      return data.data.map((c: { id: string; name: string; product_count?: number }) => ({
        id: c.id,
        name: c.name || c.id,
        product_count: c.product_count,
      }));
    } catch (err) {
      logger.error(`Failed to fetch catalogs for business ${businessId}`, err);
      return [];
    }
  }

  /**
   * Fetches Meta Pixels & Datasets under a Meta Business.
   * Modern Meta accounts manage Pixels under the /datasets endpoint.
   */
  async getPixels(businessId: string): Promise<Array<{ id: string; name: string }>> {
    if (!this.accessToken || !businessId) return [];
    const pixelsMap = new Map<string, { id: string; name: string }>();

    // 1. Check datasets (Modern Meta Events Manager Datasets, e.g. Dhaval's Market Data)
    try {
      const datasetsUrl = `https://graph.facebook.com/${this.version}/${encodeURIComponent(businessId)}/datasets?fields=id,name&access_token=${encodeURIComponent(this.accessToken)}`;
      const res = await fetch(datasetsUrl, { signal: AbortSignal.timeout(8000) });
      const data = await res.json();
      if (Array.isArray(data.data)) {
        data.data.forEach((p: { id: string; name: string }) => {
          pixelsMap.set(p.id, { id: p.id, name: `${p.id} - ${p.name || 'Dataset'}` });
        });
      }
    } catch (err) {
      logger.warn('Failed to fetch datasets', { error: String(err) });
    }

    // 2. Check adspixels
    try {
      const adsPixelsUrl = `https://graph.facebook.com/${this.version}/${encodeURIComponent(businessId)}/adspixels?fields=id,name,is_unavailable&access_token=${encodeURIComponent(this.accessToken)}`;
      const res = await fetch(adsPixelsUrl, { signal: AbortSignal.timeout(8000) });
      const data = await res.json();
      if (Array.isArray(data.data)) {
        data.data.forEach((p: { id: string; name: string }) => {
          if (!pixelsMap.has(p.id)) {
            pixelsMap.set(p.id, { id: p.id, name: `${p.id} - ${p.name || 'Pixel'}` });
          }
        });
      }
    } catch (err) {
      logger.warn('Failed to fetch adspixels', { error: String(err) });
    }

    // 3. Check owned_pixels
    try {
      const ownedPixelsUrl = `https://graph.facebook.com/${this.version}/${encodeURIComponent(businessId)}/owned_pixels?fields=id,name&access_token=${encodeURIComponent(this.accessToken)}`;
      const res = await fetch(ownedPixelsUrl, { signal: AbortSignal.timeout(8000) });
      const data = await res.json();
      if (Array.isArray(data.data)) {
        data.data.forEach((p: { id: string; name: string }) => {
          if (!pixelsMap.has(p.id)) {
            pixelsMap.set(p.id, { id: p.id, name: `${p.id} - ${p.name || 'Pixel'}` });
          }
        });
      }
    } catch (err) {
      logger.warn('Failed to fetch owned_pixels', { error: String(err) });
    }

    // 4. Check user ad accounts for associated pixels
    try {
      const adAccountsUrl = `https://graph.facebook.com/${this.version}/me/adaccounts?fields=id,name,adspixels{id,name}&access_token=${encodeURIComponent(this.accessToken)}`;
      const res = await fetch(adAccountsUrl, { signal: AbortSignal.timeout(8000) });
      const data = await res.json();
      if (Array.isArray(data.data)) {
        data.data.forEach((acc: any) => {
          if (Array.isArray(acc.adspixels?.data)) {
            acc.adspixels.data.forEach((p: { id: string; name: string }) => {
              if (!pixelsMap.has(p.id)) {
                pixelsMap.set(p.id, { id: p.id, name: `${p.id} - ${p.name || 'Pixel'}` });
              }
            });
          }
        });
      }
    } catch {}

    return Array.from(pixelsMap.values());
  }

  /**
   * Creates a new Meta Dataset / Pixel directly on Meta under the specified Business Portfolio.
   */
  async createDataset(businessId: string, name: string): Promise<{ id: string; name: string } | null> {
    if (!this.accessToken || !businessId) return null;
    const url = `https://graph.facebook.com/${this.version}/${encodeURIComponent(businessId)}/datasets?access_token=${encodeURIComponent(this.accessToken)}`;
    try {
      const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name }),
        signal: AbortSignal.timeout(8000),
      });
      const data = await res.json();
      if (data.id) {
        return { id: data.id, name };
      }
      logger.warn('Meta createDataset failed', { error: data.error?.message || data.error });
      return null;
    } catch (err) {
      logger.error('Failed to create dataset on Meta', err);
      return null;
    }
  }

  /**
   * Syncs products directly to Meta Catalog via Batch Items API.
   */
  async syncCatalogBatch(catalogId: string, products: CatalogProductRecord[]): Promise<{
    success: boolean;
    handles?: string[];
    errors?: Array<{ retailer_id: string; message: string }>;
  }> {
    const url = `https://graph.facebook.com/${this.version}/${catalogId}/items_batch?access_token=${encodeURIComponent(this.accessToken)}`;

    const requests: MetaCatalogBatchRequest[] = products.map((p) => {
      const variantId = p.shopify_variant_id.replace(/^.*\//, '');
      const productId = p.shopify_product_id.replace(/^.*\//, '');
      const itemId = `shopify_US_${productId}_${variantId}`;

      return {
        method: 'UPDATE',
        retailer_id: itemId,
        data: {
          item_group_id: `shopify_US_${productId}`,
          title: p.variant_title ? `${p.title} - ${p.variant_title}` : p.title,
          description: p.description || p.title,
          availability: p.availability,
          condition: p.condition,
          price: `${p.price.toFixed(2)} ${p.currency}`,
          url: p.product_url,
          image_url: p.image_url,
          brand: p.brand,
          google_product_category: p.google_product_category,
          fb_product_category: p.fb_product_category,
          custom_label_0: p.custom_label_0,
        },
      };
    });

    try {
      const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ item_type: 'PRODUCT_ITEM', requests }),
        signal: AbortSignal.timeout(10000),
      });
      const data = await res.json();
      if (data.error) {
        throw new Error(data.error.message || 'Meta Catalog Batch Sync Failed');
      }
      return {
        success: true,
        handles: data.handles || [data.id],
      };
    } catch (err) {
      return {
        success: false,
        errors: [{ retailer_id: 'all', message: err instanceof Error ? err.message : String(err) }],
      };
    }
  }
}
