import { db } from '@/db/client';
import { CatalogProductRecord } from '@/types';
import { decrypt } from '@/lib/crypto/encryption';
import { ShopifyClient } from './client';

export interface ShopifyVariant {
  id: string | number;
  product_id?: string | number;
  title: string;
  price: string | number;
  compare_at_price?: string | number | null;
  sku?: string;
  barcode?: string;
  inventory_quantity?: number;
  inventory_management?: string | null;
  inventory_policy?: string;
  image_id?: string | number;
  image?: { src: string };
  selected_options?: Array<{ name: string; value: string }>;
  availability?: 'in stock' | 'out of stock' | 'preorder' | 'available for order';
  availableForSale?: boolean;
  weight?: number | null;
  weight_unit?: string | null;
}

export interface ShopifyProduct {
  id: string | number;
  title: string;
  handle: string;
  body_html?: string;
  description?: string;
  vendor?: string;
  product_type?: string;
  tags?: string[];
  image?: { src: string };
  images?: Array<{ id?: string | number; src: string } | string>;
  variants?: ShopifyVariant[];
  currency?: string;
  google_product_category?: string;
  fb_product_category?: string;
  video_url?: string;
}

export interface ProductQueryOptions {
  search?: string;
  cursor?: string;
  limit?: number;
  collectionIds?: string[];
  tags?: string[];
  productIds?: string[];
  excludeCollectionIds?: string[];
  excludeTags?: string[];
  excludeProductIds?: string[];
  excludeOutOfStock?: boolean;
}

export interface StoreCollectionItem {
  id: string;
  title: string;
  handle: string;
  products_count: number;
  image?: string | null;
}

export class ShopifyProductService {
  /**
   * Fetches products for a specific shop with filtering, search, and exclusions.
   */
  static async getProducts(shopId: string, options: ProductQueryOptions = {}): Promise<{
    products: CatalogProductRecord[];
    totalCount: number;
    hasMore: boolean;
  }> {
    const limit = options.limit || 50;
    const allProducts = await db.getProductsByShopId(shopId);

    let filtered = allProducts;

    // Filter by search query (title or SKU)
    if (options.search) {
      const q = options.search.toLowerCase().trim();
      filtered = filtered.filter(
        (p: any) =>
          p.title?.toLowerCase().includes(q) ||
          p.sku?.toLowerCase().includes(q) ||
          p.vendor?.toLowerCase().includes(q)
      );
    }

    // Specific product IDs filter
    if (options.productIds && options.productIds.length > 0) {
      const idSet = new Set(options.productIds.map((id) => this.cleanShopifyId(id)));
      filtered = filtered.filter((p) => idSet.has(this.cleanShopifyId(p.shopify_product_id)));
    }

    // Specific tags filter
    if (options.tags && options.tags.length > 0) {
      const tagSet = new Set(options.tags.map((t) => t.toLowerCase()));
      filtered = filtered.filter((p: any) => {
        const pTags = Array.isArray(p.tags) ? p.tags : (p.custom_label_1 ? [p.custom_label_1] : []);
        return pTags.some((t: string) => tagSet.has(t.toLowerCase()));
      });
    }

    // Exclusions: Product IDs
    if (options.excludeProductIds && options.excludeProductIds.length > 0) {
      const excludeSet = new Set(options.excludeProductIds.map((id) => this.cleanShopifyId(id)));
      filtered = filtered.filter((p) => !excludeSet.has(this.cleanShopifyId(p.shopify_product_id)));
    }

    // Exclusions: Tags
    if (options.excludeTags && options.excludeTags.length > 0) {
      const excludeTagSet = new Set(options.excludeTags.map((t) => t.toLowerCase()));
      filtered = filtered.filter((p: any) => {
        const pTags = Array.isArray(p.tags) ? p.tags : (p.custom_label_1 ? [p.custom_label_1] : []);
        return !pTags.some((t: string) => excludeTagSet.has(t.toLowerCase()));
      });
    }

    const totalCount = filtered.length;
    const paginated = filtered.slice(0, limit);

    return {
      products: paginated,
      totalCount,
      hasMore: totalCount > limit,
    };
  }

  /**
   * Helper for modal product pagination
   */
  static async fetchProductsPaginated(params: {
    shopDomain?: string;
    accessToken?: string;
    query?: string;
    page?: number;
    limit?: number;
  }): Promise<{
    products: ShopifyProduct[];
    pagination: { page: number; totalPages: number; total: number; limit: number };
  }> {
    const page = params.page || 1;
    const limit = params.limit || 20;

    let shop = null;
    if (params.shopDomain) {
      shop = await db.getShopByDomain(params.shopDomain);
    }
    if (!shop && process.env.NODE_ENV !== 'production') {
      shop = await db.getDefaultShop();
    }
    if (!shop) {
      return { products: [], pagination: { page, totalPages: 0, total: 0, limit } };
    }

    let dbProducts = await db.getProductsByShopId(shop.id);
    if (dbProducts.length === 0) {
      try {
        let token = params.accessToken || '';
        if (!token && shop.access_token_encrypted) {
          try {
            const dec = decrypt(shop.access_token_encrypted);
            if (dec && !dec.startsWith('mock_')) token = dec;
          } catch {}
        }
        const client = new ShopifyClient(shop.shopify_domain, token);
        const live = await client.fetchAllProductsForCatalog(shop.id);
        if (live && live.length > 0) {
          await db.clearProductsByShopId(shop.id);
          for (const p of live) {
            await db.upsertProduct(p);
          }
          dbProducts = await db.getProductsByShopId(shop.id);
        }
      } catch (err: any) {
        console.warn('[ShopifyProductService] Auto-fetch in fetchProductsPaginated note:', err.message);
      }
    }
    let filtered = dbProducts;

    if (params.query) {
      const q = params.query.toLowerCase().trim();
      filtered = filtered.filter(
        p => p.title.toLowerCase().includes(q) || (p.sku && p.sku.toLowerCase().includes(q))
      );
    }

    // Group variant rows into product objects
    const productMap = new Map<string, ShopifyProduct>();
    for (const r of filtered) {
      const prodId = this.cleanShopifyId(r.shopify_product_id);
      let existing = productMap.get(prodId);
      if (!existing) {
        const allImgUrls = [r.image_url, ...(r.additional_images || [])]
          .filter(Boolean)
          .filter((u: string) => !u.includes('placeholder.com'));
        existing = {
          id: prodId,
          title: r.title,
          handle: r.product_url ? r.product_url.split('/products/')[1]?.split('?')[0] || prodId : prodId,
          description: r.description,
          body_html: r.body_html || r.description,
          vendor: r.brand || 'Store',
          product_type: r.product_type || r.custom_label_0 || '',
          tags: r.custom_label_1 ? r.custom_label_1.split(', ') : [],
          image: allImgUrls[0] ? { src: allImgUrls[0] } : undefined,
          images: allImgUrls.map(url => ({ src: url })),
          currency: r.currency || 'USD',
          google_product_category: r.google_product_category || undefined,
          fb_product_category: r.fb_product_category || undefined,
          video_url: r.video_url || undefined,
          variants: [],
        };
        productMap.set(prodId, existing);
      }

      // Parse options from custom_label_2 (e.g. "Size: 154, Color: Blue")
      const parsedOptions: Array<{ name: string; value: string }> = [];
      if (r.custom_label_2) {
        const parts = r.custom_label_2.split(',');
        for (const part of parts) {
          const [name, val] = part.split(':').map((s: string) => s.trim());
          if (name && val) {
            parsedOptions.push({ name, value: val });
          }
        }
      }

      existing.variants!.push({
        id: this.cleanShopifyId(r.shopify_variant_id),
        product_id: prodId,
        title: r.variant_title || 'Default Title',
        price: r.price,
        compare_at_price: r.compare_at_price,
        sku: r.sku || '',
        barcode: r.barcode || undefined,
        availability: r.availability,
        availableForSale: r.availability === 'in stock',
        inventory_quantity: r.inventory_quantity || 1,
        weight: r.weight,
        weight_unit: r.weight_unit,
        image: r.image_url && !r.image_url.includes('placeholder.com') ? { src: r.image_url } : undefined,
        selected_options: parsedOptions.length > 0 ? parsedOptions : undefined,
      });
    }

    const productList = Array.from(productMap.values());
    const total = productList.length;
    const totalPages = Math.max(1, Math.ceil(total / limit));
    const start = (page - 1) * limit;
    const paginated = productList.slice(start, start + limit);

    return {
      products: paginated,
      pagination: {
        page,
        totalPages,
        total,
        limit,
      },
    };
  }

  /**
   * Helper to retrieve products structured for catalog syncing
   */
  static async getProductsForCatalog(params: {
    shopDomain: string;
    accessToken: string;
    syncType: string;
    collectionIds?: string[];
    tags?: string[];
    productIds?: string[];
    excludeOutOfStock?: boolean;
    excludeTags?: string[];
    excludeCollectionIds?: string[];
    excludeProductIds?: string[];
  }): Promise<ShopifyProduct[]> {
    let shop = params.shopDomain ? await db.getShopByDomain(params.shopDomain) : null;
    if (!shop && process.env.NODE_ENV !== 'production') {
      shop = await db.getDefaultShop();
    }
    if (!shop) {
      return [];
    }

    let dbProducts = await db.getProductsByShopId(shop.id);
    if (dbProducts.length === 0) {
      try {
        let token = params.accessToken || '';
        if (!token && shop.access_token_encrypted) {
          try {
            const dec = decrypt(shop.access_token_encrypted);
            if (dec && !dec.startsWith('mock_')) token = dec;
          } catch {}
        }
        const client = new ShopifyClient(shop.shopify_domain, token);
        const live = await client.fetchAllProductsForCatalog(shop.id);
        if (live && live.length > 0) {
          await db.clearProductsByShopId(shop.id);
          for (const p of live) {
            await db.upsertProduct(p);
          }
          dbProducts = await db.getProductsByShopId(shop.id);
        }
      } catch (err: any) {
        console.warn('[ShopifyProductService] Auto-fetch in getProductsForCatalog note:', err.message);
      }
    }
    let filtered = dbProducts;

    const parseProductTags = (p: any): string[] => {
      if (Array.isArray(p.tags)) return p.tags;
      if (typeof p.tags === 'string') {
        try {
          const parsed = JSON.parse(p.tags);
          if (Array.isArray(parsed)) return parsed;
        } catch {}
        return p.tags.split(',').map((t: string) => t.trim()).filter(Boolean);
      }
      if (p.custom_label_1) {
        return p.custom_label_1.split(',').map((t: string) => t.trim()).filter(Boolean);
      }
      return [];
    };

    const hasSpecificProducts = Boolean(params.productIds && params.productIds.length > 0);
    const hasCollections = Boolean(params.collectionIds && params.collectionIds.length > 0);
    const hasTags = Boolean(params.tags && params.tags.length > 0);

    if (params.syncType === 'all') {
      filtered = [...dbProducts];
    } else {
      // 'selected' mode: union of matching collections, tags, and specific products
      if (!hasSpecificProducts && !hasCollections && !hasTags) {
        filtered = [...dbProducts];
      } else {
        const includedIds = new Set<string>();

        // 1. Specific product IDs
        if (hasSpecificProducts) {
          const idSet = new Set(params.productIds!.map(id => this.cleanShopifyId(id)));
          for (const p of dbProducts) {
            if (idSet.has(this.cleanShopifyId(p.shopify_product_id))) {
              includedIds.add(String(p.id));
            }
          }
        }

        // 2. Selected collections
        if (hasCollections) {
          const colSet = new Set(
            params.collectionIds!.map(c => c.toLowerCase().trim()).filter(Boolean)
          );
          for (const p of dbProducts) {
            const rawLabel = (p.custom_label_0 || '').trim().toLowerCase();
            const colId = rawLabel.replace(/[^a-z0-9]+/g, '-');
            if (
              colSet.has(rawLabel) ||
              colSet.has(colId) ||
              params.collectionIds!.some(c => c.toLowerCase().trim() === rawLabel)
            ) {
              includedIds.add(String(p.id));
            }
          }
        }

        // 3. Selected tags
        if (hasTags) {
          const tagSet = new Set(params.tags!.map(t => t.toLowerCase().trim()).filter(Boolean));
          for (const p of dbProducts) {
            const pTags = parseProductTags(p);
            if (pTags.some(t => tagSet.has(t.toLowerCase().trim()))) {
              includedIds.add(String(p.id));
            }
          }
        }

        filtered = dbProducts.filter(p => includedIds.has(String(p.id)));
      }
    }

    // Exclusions: Out of stock
    if (params.excludeOutOfStock) {
      filtered = filtered.filter(p => {
        const avail = (p.availability || '').toLowerCase();
        const inStockText = avail.includes('in stock') || avail.includes('available') || avail === 'in_stock';
        const qty = Number(p.inventory_quantity || 0);
        return inStockText || qty > 0;
      });
    }

    // Exclusions: Specific product IDs
    if (params.excludeProductIds && params.excludeProductIds.length > 0) {
      const excludeProdSet = new Set(params.excludeProductIds.map(id => this.cleanShopifyId(id)));
      filtered = filtered.filter(p => !excludeProdSet.has(this.cleanShopifyId(p.shopify_product_id)));
    }

    // Exclusions: Collections
    if (params.excludeCollectionIds && params.excludeCollectionIds.length > 0) {
      const excludeColSet = new Set(
        params.excludeCollectionIds.map(c => c.toLowerCase().trim()).filter(Boolean)
      );
      filtered = filtered.filter(p => {
        const rawLabel = (p.custom_label_0 || '').trim().toLowerCase();
        const colId = rawLabel.replace(/[^a-z0-9]+/g, '-');
        const isExcluded =
          excludeColSet.has(rawLabel) ||
          excludeColSet.has(colId) ||
          params.excludeCollectionIds!.some(c => c.toLowerCase().trim() === rawLabel);
        return !isExcluded;
      });
    }

    // Exclusions: Tags
    if (params.excludeTags && params.excludeTags.length > 0) {
      const excludeTagSet = new Set(params.excludeTags.map(t => t.toLowerCase().trim()).filter(Boolean));
      filtered = filtered.filter(p => {
        const pTags = parseProductTags(p);
        return !pTags.some(t => excludeTagSet.has(t.toLowerCase().trim()));
      });
    }

    // Group into ShopifyProduct structure
    const productMap = new Map<string, ShopifyProduct>();
    for (const r of filtered) {
      const prodId = this.cleanShopifyId(r.shopify_product_id);
      let existing = productMap.get(prodId);
      if (!existing) {
        const allImgUrls = [r.image_url, ...(r.additional_images || [])]
          .filter(Boolean)
          .filter((u: string) => !u.includes('placeholder.com'));
        existing = {
          id: prodId,
          title: r.title,
          handle: r.product_url ? r.product_url.split('/products/')[1]?.split('?')[0] || prodId : prodId,
          description: r.description,
          body_html: r.body_html || r.description,
          vendor: r.brand || 'Store',
          product_type: r.product_type || r.custom_label_0 || '',
          tags: r.custom_label_1 ? r.custom_label_1.split(', ') : [],
          image: allImgUrls[0] ? { src: allImgUrls[0] } : undefined,
          images: allImgUrls.map(url => ({ src: url })),
          currency: r.currency || 'USD',
          google_product_category: r.google_product_category || undefined,
          fb_product_category: r.fb_product_category || undefined,
          video_url: r.video_url || undefined,
          variants: [],
        };
        productMap.set(prodId, existing);
      }

      // Parse options from custom_label_2 (e.g. "Size: 154, Color: Blue")
      const parsedOptions: Array<{ name: string; value: string }> = [];
      if (r.custom_label_2) {
        const parts = r.custom_label_2.split(',');
        for (const part of parts) {
          const [name, val] = part.split(':').map((s: string) => s.trim());
          if (name && val) {
            parsedOptions.push({ name, value: val });
          }
        }
      }

      existing.variants!.push({
        id: this.cleanShopifyId(r.shopify_variant_id),
        product_id: prodId,
        title: r.variant_title || 'Default Title',
        price: r.price,
        compare_at_price: r.compare_at_price,
        sku: r.sku || '',
        barcode: r.barcode || undefined,
        availability: r.availability,
        availableForSale: r.availability === 'in stock',
        inventory_quantity: r.inventory_quantity || 1,
        weight: r.weight,
        weight_unit: r.weight_unit,
        image: r.image_url && !r.image_url.includes('placeholder.com') ? { src: r.image_url } : undefined,
        selected_options: parsedOptions.length > 0 ? parsedOptions : undefined,
      });
    }

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

  /**
   * Returns unique product collections available for the shop.
   */
  static async getCollections(shopId: string): Promise<StoreCollectionItem[]> {
    let products = await db.getProductsByShopId(shopId);
    if (products.length === 0) {
      try {
        const shop = await db.getShopById(shopId);
        if (shop && shop.access_token_encrypted) {
          const dec = decrypt(shop.access_token_encrypted);
          if (dec && !dec.startsWith('mock_')) {
            const client = new ShopifyClient(shop.shopify_domain, dec);
            const live = await client.fetchAllProductsForCatalog(shop.id);
            if (live && live.length > 0) {
              await db.clearProductsByShopId(shop.id);
              for (const p of live) await db.upsertProduct(p);
              products = await db.getProductsByShopId(shopId);
            }
          }
        }
      } catch (err: any) {
        console.warn('[ShopifyProductService] Auto-fetch in getCollections note:', err.message);
      }
    }
    const collectionMap = new Map<string, { id: string; title: string; count: number }>();

    for (const p of products) {
      if (p.custom_label_0 || p.product_url) {
        const name = p.custom_label_0 || 'General Collection';
        const id = name.toLowerCase().replace(/[^a-z0-9]+/g, '-');
        const existing = collectionMap.get(id);
        if (existing) {
          existing.count += 1;
        } else {
          collectionMap.set(id, { id, title: name, count: 1 });
        }
      }
    }

    return Array.from(collectionMap.values()).map((c) => ({
      id: c.id,
      title: c.title,
      handle: c.id,
      products_count: c.count,
    }));
  }

  static async fetchCollections(params?: { shopDomain?: string; accessToken?: string }): Promise<StoreCollectionItem[]> {
    let shop = null;
    if (params?.shopDomain) {
      shop = await db.getShopByDomain(params.shopDomain);
    }
    if (!shop && process.env.NODE_ENV !== 'production') {
      shop = await db.getDefaultShop();
    }
    if (!shop) {
      return [];
    }
    return this.getCollections(shop.id);
  }

  /**
   * Returns unique product tags across all products for the shop.
   */
  static async getTags(shopId: string): Promise<string[]> {
    let products = await db.getProductsByShopId(shopId);
    if (products.length === 0) {
      try {
        const shop = await db.getShopById(shopId);
        if (shop && shop.access_token_encrypted) {
          const dec = decrypt(shop.access_token_encrypted);
          if (dec && !dec.startsWith('mock_')) {
            const client = new ShopifyClient(shop.shopify_domain, dec);
            const live = await client.fetchAllProductsForCatalog(shop.id);
            if (live && live.length > 0) {
              await db.clearProductsByShopId(shop.id);
              for (const p of live) await db.upsertProduct(p);
              products = await db.getProductsByShopId(shopId);
            }
          }
        }
      } catch (err: any) {
        console.warn('[ShopifyProductService] Auto-fetch in getTags note:', err.message);
      }
    }
    const tagSet = new Set<string>();

    for (const p of products) {
      if (p.custom_label_1) {
        p.custom_label_1.split(',').forEach(t => {
          if (t && t.trim()) tagSet.add(t.trim());
        });
      }
    }

    return Array.from(tagSet).sort();
  }

  static async fetchTags(params?: { shopDomain?: string; accessToken?: string }): Promise<string[]> {
    let shop = null;
    if (params?.shopDomain) {
      shop = await db.getShopByDomain(params.shopDomain);
    }
    if (!shop && process.env.NODE_ENV !== 'production') {
      shop = await db.getDefaultShop();
    }
    if (!shop) {
      return [];
    }
    return this.getTags(shop.id);
  }

  /**
   * Returns product and variant counts for a shop.
   */
  static async getStoreProductCounts(shopId: string): Promise<{ productCount: number; variantCount: number }> {
    const products = await db.getProductsByShopId(shopId);
    const uniqueProducts = new Set(products.map((p) => p.shopify_product_id));
    return {
      productCount: uniqueProducts.size,
      variantCount: products.length,
    };
  }

  private static cleanShopifyId(id: string | number): string {
    if (!id) return '';
    return String(id).replace(/^gid:\/\/shopify\/Product\//, '').replace(/^gid:\/\/shopify\/ProductVariant\//, '');
  }
}
export type ShopifyCollection = StoreCollectionItem;
