import { CommerceConnector } from '../interfaces/connector.interface';
import { UniversalProduct, UniversalCategory, UniversalOrder } from '../interfaces/universal-models.interface';
import axios, { AxiosInstance } from 'axios';

export class MetaCatalogConnector implements CommerceConnector {
  private axiosClient: AxiosInstance | null = null;
  private readonly isSandbox: boolean = false;
  private readonly catalogId: string;
  private readonly accessToken: string;
  private readonly apiVersion = 'v19.0';

  constructor(credentials: Record<string, any>) {
    this.catalogId = (credentials.catalogId || credentials.metaCatalogId || '').trim();
    this.accessToken = (credentials.accessToken || credentials.metaAccessToken || '').trim();
    this.isSandbox = credentials.isSandbox || !this.catalogId || !this.accessToken;

    if (!this.isSandbox) {
      this.axiosClient = axios.create({
        baseURL: `https://graph.facebook.com/${this.apiVersion}`,
        headers: {
          Authorization: `Bearer ${this.accessToken}`,
          'Content-Type': 'application/json',
        },
        timeout: 15000,
      });
    }
  }

  async testConnection(): Promise<boolean> {
    if (this.isSandbox) return true;
    if (!this.axiosClient) return false;

    try {
      const response = await this.axiosClient.get(`/${this.catalogId}`, {
        params: { fields: 'id,name' },
      });
      return !!response.data.id;
    } catch (err: any) {
      const detail = err.response?.data?.error?.message || err.response?.data?.error?.error_user_msg || err.message;
      throw new Error(detail || 'Could not verify Meta Catalog ID and System User Token.');
    }
  }

  async fetchProducts(): Promise<UniversalProduct[]> {
    if (this.isSandbox) {
      return [
        {
          externalId: 'meta_mock_1',
          name: 'Meta Native Product Example',
          description: 'Synced native catalog item for WhatsApp Business catalog',
          sku: 'META-SKU-01',
          price: 29.99,
          currency: 'USD',
          stockQuantity: 100,
          stockStatus: 'instock',
          imageUrl: undefined,
          variants: [],
        },
      ];
    }

    if (!this.axiosClient) {
      throw new Error('Meta Catalog API client is not configured');
    }

    try {
      const response = await this.axiosClient.get(`/${this.catalogId}/products`, {
        params: { fields: 'id,name,description,price,currency,image_url,retailer_id,availability' },
      });

      return (response.data.data || []).map((p: any) => ({
        externalId: String(p.id),
        name: p.name,
        description: p.description || undefined,
        sku: p.retailer_id || undefined,
        price: p.price ? parseFloat(p.price) / 100 : 0,
        currency: p.currency || 'USD',
        stockQuantity: p.availability === 'in stock' ? 10 : 0,
        stockStatus: p.availability === 'in stock' ? 'instock' : 'outofstock',
        imageUrl: p.image_url || undefined,
        variants: [],
      }));
    } catch (err: any) {
      throw new Error(`Failed to fetch products from Meta Catalog: ${err.message}`);
    }
  }

  async fetchCategories(): Promise<UniversalCategory[]> {
    return [
      { externalId: 'meta_cat_general', name: 'WhatsApp Catalog Products' },
    ];
  }

  async createProduct(product: UniversalProduct): Promise<{ externalId: string }> {
    if (this.isSandbox) {
      return { externalId: `mock_meta_${Math.floor(10000 + Math.random() * 90000)}` };
    }

    if (!this.axiosClient) {
      throw new Error('Meta Catalog API client is not configured');
    }

    try {
      const retailerId = (product.sku && product.sku.trim() !== '') ? product.sku.trim() : `PROD-${product.externalId || Date.now()}`;
      const imageUrl = this.normalizePublicImageUrl(product.imageUrl) || 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product';

      const itemData: any = {
        retailer_id: retailerId,
        name: product.name,
        description: product.description || product.name,
        price: Math.round((product.price || 0) * 100),
        currency: product.currency || 'USD',
        availability: product.stockStatus === 'instock' ? 'in stock' : 'out of stock',
        condition: 'new',
        url: `https://api.whatsapp.com/catalog/${this.catalogId}/item/${retailerId}`,
        image_url: imageUrl,
      };

      const batchPayload = {
        allow_upsert: true,
        requests: [
          {
            method: 'CREATE',
            data: itemData,
          },
        ],
      };

      try {
        let response: any;
        try {
          response = await this.axiosClient.post(`/${this.catalogId}/items_batch`, batchPayload);
        } catch (batchErr: any) {
          response = await this.axiosClient.post(`/${this.catalogId}/batch`, batchPayload);
        }
        return { externalId: retailerId };
      } catch (postErr: any) {
        let currentErr = postErr;
        const detailStr = String(currentErr.response?.data?.error?.message || currentErr.message || '').toLowerCase();
        if (itemData.image_url !== 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product' && (detailStr.includes('image') || detailStr.includes('url') || detailStr.includes('not found') || currentErr.response?.status === 400)) {
          batchPayload.requests[0].data.image_url = 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product';
          try {
            await this.axiosClient.post(`/${this.catalogId}/items_batch`, batchPayload);
            return { externalId: retailerId };
          } catch (retryErr: any) {
            currentErr = retryErr;
          }
        }
        throw currentErr;
      }
    } catch (err: any) {
      const detail = err.response?.data?.error?.message || err.response?.data?.error?.error_user_msg || (typeof err.response?.data === 'object' ? JSON.stringify(err.response.data) : null) || err.message;
      throw new Error(`Failed to create product in Meta Catalog: ${detail}`);
    }
  }

  private normalizePublicImageUrl(url?: string): string | undefined {
    if (!url || typeof url !== 'string') {
      return 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product';
    }
    let cleanUrl = url.trim();
    if (cleanUrl.startsWith('/')) {
      cleanUrl = `http://localhost:3001${cleanUrl}`;
    }
    if (!cleanUrl.startsWith('http')) {
      return 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product';
    }
    let publicBase = process.env.PUBLIC_URL || process.env.FRONTEND_URL || '';
    if (!publicBase || publicBase.includes('ngrok-free.dev') || publicBase.includes('localhost')) {
      try {
        const fs = require('fs');
        const path = require('path');
        const envContent = fs.readFileSync(path.join(process.cwd(), '.env'), 'utf8');
        const matchPublic = envContent.match(/PUBLIC_URL=(https?:\/\/[^\s\r\n]+)/);
        if (matchPublic && matchPublic[1] && !matchPublic[1].includes('ngrok-free.dev') && !matchPublic[1].includes('localhost')) {
          publicBase = matchPublic[1];
          process.env.PUBLIC_URL = publicBase;
        } else {
          const matchFront = envContent.match(/FRONTEND_URL=(https?:\/\/[^\s\r\n]+)/);
          if (matchFront && matchFront[1] && !matchFront[1].includes('ngrok-free.dev') && !matchFront[1].includes('localhost')) {
            publicBase = matchFront[1];
            process.env.FRONTEND_URL = publicBase;
          }
        }
      } catch (e) {
        // ignore
      }
    }
    if (cleanUrl.includes('://localhost') || cleanUrl.includes('://127.0.0.1') || cleanUrl.includes('ngrok-free.dev')) {
      if (publicBase && publicBase.startsWith('http') && !publicBase.includes('ngrok-free.dev') && !publicBase.includes('localhost')) {
        const match = cleanUrl.match(/\/(uploads\/.*)$/);
        if (match) {
          cleanUrl = `${publicBase.replace(/\/$/, '')}/${match[1]}`;
        }
      }
    }
    if (cleanUrl.includes('://localhost') || cleanUrl.includes('://127.0.0.1') || cleanUrl.includes('ngrok-free.dev')) {
      return 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product'; // Only if no live tunnel URL is available
    }
    return cleanUrl;
  }

  async updateProduct(externalProductId: string, product: UniversalProduct): Promise<boolean> {
    if (this.isSandbox) return true;
    if (!this.axiosClient) {
      throw new Error('Meta Catalog API client is not configured');
    }

    try {
      const payload: any = {
        name: product.name,
        description: product.description || product.name,
        price: Math.round((product.price || 0) * 100),
        currency: product.currency || 'USD',
        availability: product.stockStatus === 'instock' ? 'in stock' : 'out of stock',
      };
      const cleanImage = this.normalizePublicImageUrl(product.imageUrl) || 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product';
      payload.image_url = cleanImage;

      try {
        await this.axiosClient.post(`/${externalProductId}`, payload);
      } catch (putErr: any) {
        if (putErr.response?.status === 404) {
          await this.createProduct(product);
          return true;
        }
        const detailStr = String(putErr.response?.data?.error?.message || putErr.message || '').toLowerCase();
        if (payload.image_url && payload.image_url !== 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product' && (detailStr.includes('image') || detailStr.includes('url') || detailStr.includes('not found') || putErr.response?.status === 400)) {
          payload.image_url = 'https://dummyimage.com/600x600/008069/ffffff.png&text=Product';
          await this.axiosClient.post(`/${externalProductId}`, payload);
          return true;
        }
        throw putErr;
      }
      return true;
    } catch (err: any) {
      if (err.response?.status === 404) {
        await this.createProduct(product);
        return true;
      }
      const detail = err.response?.data?.error?.message || err.response?.data?.error?.error_user_msg || (typeof err.response?.data === 'object' ? JSON.stringify(err.response.data) : null) || err.message;
      throw new Error(`Failed to update product in Meta Catalog (${externalProductId}): ${detail}`);
    }
  }

  async deleteProduct(externalProductId: string, product?: any): Promise<boolean> {
    if (this.isSandbox) return true;
    if (!this.axiosClient) {
      throw new Error('Meta Catalog API client is not configured');
    }

    // 1. If externalProductId looks like a long Facebook Node ID (>= 12 digits), try direct delete
    if (/^\d{12,}$/.test(externalProductId)) {
      try {
        await this.axiosClient.delete(`/${externalProductId}`);
        return true;
      } catch (err: any) {
        if (err.response?.status === 404) return true;
      }
    }

    // 2. Search Meta Catalog by retailer_id (SKU or ID) to find the true Facebook Node ID and delete it
    const retailerId = product?.sku || product?.externalProductId || externalProductId;
    if (retailerId && typeof retailerId === 'string' && retailerId.trim()) {
      try {
        const searchRes = await this.axiosClient.get('/products', {
          params: { filter: JSON.stringify({ retailer_id: { eq: retailerId.trim() } }) },
        });
        if (searchRes.data?.data && Array.isArray(searchRes.data.data)) {
          for (const item of searchRes.data.data) {
            if (item.id) {
              try {
                await this.axiosClient.delete(`/${item.id}`);
              } catch {
                // Ignore if already deleted
              }
            }
          }
        }
      } catch {
        // Ignore search filter fallback errors
      }
    }

    return true;
  }

  async checkStock(): Promise<number> {
    return 10;
  }

  async updateStock(externalProductId: string, quantity: number): Promise<boolean> {
    if (this.isSandbox) return true;
    if (!this.axiosClient) return false;

    try {
      await this.axiosClient.post(`/${externalProductId}`, {
        availability: quantity > 0 ? 'in stock' : 'out of stock',
      });
      return true;
    } catch {
      return false;
    }
  }

  async createOrder(order: UniversalOrder): Promise<{ externalOrderId: string; orderNumber: string }> {
    return { externalOrderId: `meta_ord_${Date.now()}`, orderNumber: `META-${Date.now()}` };
  }

  async updateOrderStatus(): Promise<boolean> {
    return true;
  }

  async updatePaymentStatus(): Promise<boolean> {
    return true;
  }

  async fetchOrder(externalOrderId: string): Promise<UniversalOrder> {
    throw new Error('Meta Catalog does not support order queries directly.');
  }

  async registerWebhooks(): Promise<boolean> {
    return true;
  }
}
