import { MetaBatchItemRequest } from '@/types/catalog';
import { META_CONFIG } from '@/config/meta';

const META_GRAPH_BASE = META_CONFIG.graphBaseUrl;

export interface MetaCatalogResponse {
  id: string;
  name?: string;
  vertical?: string;
}

export interface MetaBatchResponse {
  handles?: string[];
  validation_status?: Array<{
    retailer_id: string;
    errors?: Array<{ code: number; message: string }>;
    warnings?: Array<{ code: number; message: string }>;
  }>;
  error?: {
    message: string;
    type: string;
    code: number;
    fbtrace_id?: string;
  };
}

export interface MetaBusinessAccount {
  id: string;
  name: string;
  verification_status?: string;
}

export interface MetaPixelAccount {
  id: string;
  name: string;
}

export class MetaCatalogService {
  /**
   * Fetch connected user's Business Manager accounts.
   */
  static async getBusinessAccounts(accessToken: string): Promise<MetaBusinessAccount[]> {
    try {
      const url = `${META_GRAPH_BASE}/me/businesses?fields=id,name,verification_status&limit=100&access_token=${encodeURIComponent(accessToken)}`;
      const res = await fetch(url, {
        method: 'GET',
        signal: AbortSignal.timeout(4000),
      });
      const data = await res.json();

      if (data.error) {
        console.warn('[MetaCatalogService] getBusinessAccounts error:', data.error);
        return [];
      }

      return (data.data || []).map((biz: any) => ({
        id: biz.id,
        name: biz.name || `Business (${biz.id})`,
        verification_status: biz.verification_status,
      }));
    } catch (err: any) {
      console.warn('[MetaCatalogService] getBusinessAccounts exception:', err.message);
      return [];
    }
  }

  /**
   * Fetch Pixels for a given Business Account or user.
   */
  static async getPixels(accessToken: string, businessId?: string): Promise<MetaPixelAccount[]> {
    try {
      const endpoint = businessId
        ? `${META_GRAPH_BASE}/${businessId}/adspixels?fields=id,name&limit=100&access_token=${encodeURIComponent(accessToken)}`
        : `${META_GRAPH_BASE}/me/adspixels?fields=id,name&limit=100&access_token=${encodeURIComponent(accessToken)}`;

      const res = await fetch(endpoint, {
        method: 'GET',
        signal: AbortSignal.timeout(4000),
      });
      const data = await res.json();

      if (data.error) {
        console.warn('[MetaCatalogService] getPixels error:', data.error);
        return [];
      }

      return (data.data || []).map((px: any) => ({
        id: px.id,
        name: px.name || `Pixel ${px.id}`,
      }));
    } catch (err: any) {
      console.warn('[MetaCatalogService] getPixels exception:', err.message);
      return [];
    }
  }

  /**
   * Creates a new Product Catalog in Meta under the specified Business Manager.
   * POST /{business_id}/owned_product_catalogs
   */
  static async createCatalog(
    businessId: string,
    catalogName: string,
    accessToken: string
  ): Promise<{ success: boolean; catalogId?: string; error?: string }> {
    try {
      const url = `${META_GRAPH_BASE}/${businessId}/owned_product_catalogs`;
      const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          name: catalogName,
          access_token: accessToken,
        }),
        signal: AbortSignal.timeout(4000),
      });

      const data = await res.json();

      if (data.error) {
        console.warn('[MetaCatalogService] createCatalog error:', data.error);
        return {
          success: false,
          error: data.error.message || `Meta API Error (${data.error.code})`,
        };
      }

      return {
        success: true,
        catalogId: data.id,
      };
    } catch (err: any) {
      console.warn('[MetaCatalogService] createCatalog network notice:', err.message);
      return {
        success: false,
        error: err.message || 'Network exception connecting to Meta Graph API',
      };
    }
  }

  /**
   * Deletes a Product Catalog in Meta.
   * DELETE /{catalog_id}
   */
  static async deleteCatalog(
    catalogId: string,
    accessToken: string
  ): Promise<{ success: boolean; error?: string }> {
    try {
      const url = `${META_GRAPH_BASE}/${catalogId}?access_token=${encodeURIComponent(accessToken)}`;
      const res = await fetch(url, {
        method: 'DELETE',
        signal: AbortSignal.timeout(4000),
      });

      const data = await res.json();

      if (data.error) {
        console.warn('[MetaCatalogService] deleteCatalog error:', data.error);
        return {
          success: false,
          error: data.error.message || `Meta API Error (${data.error.code})`,
        };
      }

      return { success: true };
    } catch (err: any) {
      console.warn('[MetaCatalogService] deleteCatalog exception:', err.message);
      return {
        success: false,
        error: err.message || 'Network exception deleting Meta Catalog',
      };
    }
  }

  /**
   * Connects / links a Pixel to a Meta Catalog as an external event source.
   * POST /{catalog_id}/external_event_sources
   */
  static async linkPixel(
    catalogId: string,
    pixelId: string,
    accessToken: string
  ): Promise<{ success: boolean; error?: string }> {
    try {
      const url = `${META_GRAPH_BASE}/${catalogId}/external_event_sources`;
      const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          external_event_sources: [pixelId],
          access_token: accessToken,
        }),
        signal: AbortSignal.timeout(4000),
      });

      const data = await res.json();

      if (data.error) {
        console.warn('[MetaCatalogService] linkPixel error:', data.error);
        return {
          success: false,
          error: data.error.message || 'Failed to link Pixel',
        };
      }

      return { success: true };
    } catch (err: any) {
      console.warn('[MetaCatalogService] linkPixel exception:', err.message);
      return { success: false, error: err.message };
    }
  }

  /**
   * Unlinks a Pixel from a Meta Catalog.
   * DELETE /{catalog_id}/external_event_sources?external_event_sources=["..."]
   */
  static async unlinkPixel(
    catalogId: string,
    pixelId: string,
    accessToken: string
  ): Promise<{ success: boolean; error?: string }> {
    try {
      const url = `${META_GRAPH_BASE}/${catalogId}/external_event_sources?external_event_sources=${encodeURIComponent(
        JSON.stringify([pixelId])
      )}&access_token=${encodeURIComponent(accessToken)}`;

      const res = await fetch(url, {
        method: 'DELETE',
        signal: AbortSignal.timeout(4000),
      });

      const data = await res.json();

      if (data.error) {
        console.warn('[MetaCatalogService] unlinkPixel error:', data.error);
        return {
          success: false,
          error: data.error.message || 'Failed to unlink Pixel',
        };
      }

      return { success: true };
    } catch (err: any) {
      console.warn('[MetaCatalogService] unlinkPixel exception:', err.message);
      return { success: false, error: err.message };
    }
  }

  /**
   * Fetches all live product retailer_ids currently inside the Meta catalog.
   * Uses Graph API GET /{catalog_id}/products?fields=retailer_id&limit=1000
   */
  static async fetchCatalogProductRetailerIds(
    catalogId: string,
    accessToken: string
  ): Promise<string[]> {
    const retailerIds: string[] = [];
    try {
      let currentUrl: string | null = `${META_GRAPH_BASE}/${encodeURIComponent(catalogId)}/products?fields=retailer_id&limit=1000&access_token=${encodeURIComponent(accessToken)}`;
      let pageCount = 0;
      while (currentUrl && pageCount < 10) {
        pageCount++;
        const response: Response = await fetch(currentUrl, {
          method: 'GET',
          signal: AbortSignal.timeout(10000),
        });
        const result: any = await response.json();
        if (result.error) {
          console.warn('[MetaCatalogService] fetchCatalogProductRetailerIds error:', result.error);
          break;
        }
        if (Array.isArray(result.data)) {
          for (const item of result.data) {
            if (item.retailer_id) {
              retailerIds.push(String(item.retailer_id));
            }
          }
        }
        currentUrl = result.paging?.next || null;
      }
    } catch (err: any) {
      console.warn('[MetaCatalogService] fetchCatalogProductRetailerIds exception:', err.message);
    }
    return retailerIds;
  }

  /**
   * Sends a batch of items (CREATE / UPDATE / DELETE) to Meta Catalog.
   * Max 4999 items per batch.
   * POST /{catalog_id}/items_batch
   */
  static async sendItemsBatch(
    catalogId: string,
    requests: MetaBatchItemRequest[],
    accessToken: string
  ): Promise<{
    success: boolean;
    handles?: string[];
    errors?: Array<{ retailer_id: string; message: string }>;
    rawError?: string;
  }> {
    if (!requests || requests.length === 0) {
      return { success: true, handles: [] };
    }

    // Ensure DELETE requests have the required `data: { id: retailer_id }` structure expected by Meta Graph API
    const formattedRequests = requests.map(req => {
      if (req.method === 'DELETE') {
        const extraData = typeof req.data === 'object' && req.data !== null ? req.data : {};
        return {
          method: 'DELETE' as const,
          retailer_id: String(req.retailer_id),
          data: {
            ...extraData,
            id: String(req.retailer_id),
          },
        };
      }
      return req;
    });

    try {
      const url = `${META_GRAPH_BASE}/${catalogId}/items_batch`;
      const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          item_type: 'PRODUCT_ITEM',
          allow_upsert: true,
          requests: formattedRequests,
          access_token: accessToken,
        }),
        signal: AbortSignal.timeout(30000),
      });

      const data: any = await res.json();

      if (data.error) {
        console.warn('[MetaCatalogService] sendItemsBatch error:', data.error);
        return {
          success: false,
          rawError: data.error.message || `Meta API Error (${data.error.code})`,
        };
      }

      const errors: Array<{ retailer_id: string; message: string }> = [];
      if (data.validation_status) {
        for (const vs of data.validation_status) {
          if (vs.errors && vs.errors.length > 0) {
            errors.push({
              retailer_id: vs.retailer_id,
              message: vs.errors.map((e: any) => e.message).join('; '),
            });
          }
        }
      }

      const handles = data.handles || (data.h ? [data.h] : []);

      return {
        success: errors.length === 0,
        handles,
        errors: errors.length > 0 ? errors : undefined,
      };
    } catch (err: any) {
      console.warn('[MetaCatalogService] sendItemsBatch exception:', err.message);
      return {
        success: false,
        rawError: err.message || 'Network exception pushing items to Meta Catalog',
      };
    }
  }

  /**
   * Helper to generate the Facebook Commerce Manager Catalog URL.
   */
  static getCommerceManagerUrl(catalogId: string, businessId?: string): string {
    const cleanId = String(catalogId || '').trim();
    if (businessId) {
      return `https://business.facebook.com/commerce/catalogs/${cleanId}/home/?business_id=${businessId}`;
    }
    return `https://business.facebook.com/commerce/catalogs/${cleanId}/home/`;
  }
}
