/**
 * Products Service
 * CRUD-Operationen für Products aus Appwrite
 * Filtert nach product_account_id für Account-Scoping
 */

import { databases, databaseId } from "../lib/appwrite";
import { Query, ID } from "appwrite";
import { getAccountById, deriveMarketFromAccount, deriveCurrencyFromMarket, updateAccountLastScanAt } from "./accountsService";
import { parseViaExtensionScanProducts } from "./ebayParserService";

const productsCollectionId = import.meta.env.VITE_APPWRITE_PRODUCTS_COLLECTION_ID || "products";

/** Deutsche eBay-Zustandsbezeichnungen → product_condition Enum (längere zuerst) */
const CONDITION_DE_TO_ENUM = [
  ["neu mit etikett", "new_with_tags"],
  ["neu ohne etikett", "new_without_tags"],
  ["neu mit mängeln", "new_with_defects"],
  ["vom hersteller generalüberholt", "manufacturer_refurbished"],
  ["vom hersteller generalueberholt", "manufacturer_refurbished"],
  ["vom verkäufer generalüberholt", "seller_refurbished"],
  ["vom verkäufer generalueberholt", "seller_refurbished"],
  ["vom verkaeufer generalüberholt", "seller_refurbished"],
  ["vom verkaeufer generalueberholt", "seller_refurbished"],
  ["defekt oder unvollständig", "for_parts_or_not_working"],
  ["defekt oder unvollstaendig", "for_parts_or_not_working"],
  ["sehr gut", "very_good"],
  ["wie neu", "like_new"],
  ["ausstellerstück", "display_item"],
  ["ausstellerstueck", "display_item"],
  ["unbenutzt", "unused"],
  ["antik", "antique"],
  ["neu", "new"],
  ["gebraucht", "used"],
  ["gut", "good"],
  ["akzeptabel", "acceptable"],
];

/**
 * Mappt deutsche eBay-Zustandsangabe auf product_condition Enum.
 * @param {string|null|undefined} de - z.B. "Neu", "Gebraucht", "Neu mit Etikett"
 * @returns {string|null} Enum-Wert oder null wenn nicht zuordenbar
 */
function mapConditionDeToEnum(de) {
  if (de == null || typeof de !== "string") return null;
  const n = de.trim().toLowerCase().replace(/\s+/g, " ");
  if (!n) return null;
  for (const [phrase, enumVal] of CONDITION_DE_TO_ENUM) {
    if (n.includes(phrase)) return enumVal;
  }
  return null;
}

/**
 * Lädt alle Products für einen bestimmten Account
 * @param {string} accountId - ID des Accounts (product_account_id)
 * @param {Object} [options] - Optionale Parameter
 * @param {number} [options.limit] - Maximale Anzahl Ergebnisse (default: 25)
 * @param {number} [options.offset] - Offset für Pagination (default: 0)
 * @param {string} [options.orderBy] - Feld zum Sortieren (default: "$createdAt")
 * @param {string} [options.orderType] - Sortier-Richtung: "asc" oder "desc" (default: "desc")
 * @returns {Promise<Array>} Array von Product-Dokumenten
 */
export async function listProductsByAccount(accountId, options = {}) {
  if (!accountId) {
    console.warn("listProductsByAccount: accountId fehlt");
    return [];
  }

  const {
    limit = 25,
    offset = 0,
    orderBy = "$createdAt",
    orderType = "desc",
  } = options;

  try {
    const queries = [
      Query.equal("product_account_id", accountId),
      Query.orderDesc(orderBy), // orderType wird über Desc/Asc gehandhabt
      Query.limit(limit),
      Query.offset(offset),
    ];

    // Wenn orderType "asc" ist, verwende orderAsc statt orderDesc
    if (orderType === "asc") {
      queries[1] = Query.orderAsc(orderBy);
    }

    const response = await databases.listDocuments(
      databaseId,
      productsCollectionId,
      queries
    );

    return response.documents;
  } catch (e) {
    console.error("Fehler beim Laden der Products:", e);
    
    // Wenn Collection nicht existiert oder Berechtigungen fehlen
    if (e.code === 404 || e.code === 401 || e.type === 'collection_not_found') {
      // Placeholder: Collection existiert noch nicht
      console.warn("Products-Collection existiert noch nicht oder ist nicht verfügbar. Gebe leeres Array zurück.");
      return [];
    }
    
    throw e;
  }
}

const EXISTING_PRODUCTS_PAGE_SIZE = 100;

/**
 * Lädt alle Products eines Accounts für Duplikat-Prüfung (paginiert, Appwrite-Limit 100/Request).
 * @param {string} accountId
 * @returns {Promise<Array>}
 */
async function fetchAllProductsByAccount(accountId) {
  const all = [];
  let offset = 0;
  let hasMore = true;
  while (hasMore) {
    const page = await listProductsByAccount(accountId, {
      limit: EXISTING_PRODUCTS_PAGE_SIZE,
      offset,
      orderBy: "$createdAt",
      orderType: "asc",
    });
    all.push(...page);
    hasMore = page.length === EXISTING_PRODUCTS_PAGE_SIZE;
    offset += page.length;
  }
  return all;
}

/**
 * Lädt ein einzelnes Product nach ID
 * @param {string} productId - ID des Products
 * @returns {Promise<Object|null>} Product-Dokument oder null
 */
export async function getProductById(productId) {
  if (!productId) {
    console.warn("getProductById: productId fehlt");
    return null;
  }

  try {
    const document = await databases.getDocument(
      databaseId,
      productsCollectionId,
      productId
    );
    return document;
  } catch (e) {
    // 404 bedeutet, dass das Dokument nicht existiert
    if (e.code === 404 || e.type === 'document_not_found') {
      return null;
    }
    console.error("Fehler beim Laden des Products:", e);
    throw e;
  }
}

/**
 * Scannt Produkte für einen Account über die Extension (echte eBay-Daten)
 * @param {string} accountId - ID des Accounts
 * @returns {Promise<{ created: number, updated: number }>} Anzahl erstellter/aktualisierter Produkte
 */
export async function scanProductsForAccount(accountId) {
  if (!accountId) {
    throw new Error("accountId ist erforderlich");
  }

  try {
    // 1. Lade Account, um URL und andere Daten abzuleiten
    const account = await getAccountById(accountId);
    if (!account) {
      throw new Error("Account nicht gefunden");
    }

    if (!account.account_url) {
      throw new Error("Account-URL fehlt. Bitte Account refreshen.");
    }

    // 2. Extension aufrufen: scanne Produkte
    let items;
    try {
      items = await parseViaExtensionScanProducts(account.account_url, accountId);
    } catch (extensionError) {
      // Extension-Fehler: Parsing failed
      console.error("Extension-Fehler beim Scannen:", extensionError);
      
      // Erstelle detaillierte Fehlermeldung mit meta-Informationen
      const meta = extensionError.meta || {};
      let errorMessage = extensionError.message || "Parsing failed";
      
      // Füge meta-Details hinzu, falls vorhanden
      if (meta.pageType) {
        errorMessage += ` (Seitentyp: ${meta.pageType})`;
      }
      if (meta.reason) {
        errorMessage += ` (Grund: ${meta.reason})`;
      }
      if (meta.finalUrl) {
        errorMessage += ` (URL: ${meta.finalUrl})`;
      }
      
      const detailedError = new Error(`Extension-Fehler: ${errorMessage}`);
      detailedError.meta = meta;
      throw detailedError;
    }

    // #region agent log
    fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'productsService.js:scanProductsForAccount',message:'items from extension',data:{itemsCount:items?.length},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H4'})}).catch(()=>{});
    // #endregion
    // 3. Response-Items zu Product-Schema mappen
    const mappedProducts = items.map(item => {
      if (!item.platformProductId) {
        console.warn("Item ohne platformProductId übersprungen:", item);
        return null;
      }
      const id = String(item.platformProductId).trim();
      if (id === "123456" || id.length < 10) {
        console.warn("Item mit Platzhalter-/ungültiger ID übersprungen (eBay-IDs 10–12 Ziffern):", id);
        return null;
      }

      return {
        product_platform_product_id: item.platformProductId,
        product_title: item.title || "",
        product_price: item.price ?? undefined,
        product_currency: item.currency ?? undefined,
        product_url: item.url || "",
        product_status: item.status ?? "unknown",
        product_category: String(item.category ?? "unknown").slice(0, 255),
        product_condition: mapConditionDeToEnum(item.condition) ?? "used",
        product_quantity_sold: item.quantitySold ?? undefined,
        product_quantity_available: item.quantityAvailable ?? undefined,
        product_watch_count: item.watchCount ?? undefined,
        product_in_carts_count: item.inCartsCount ?? undefined
      };
    }).filter(Boolean); // Entferne null-Einträge
    // #region agent log
    fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'productsService.js:scanProductsForAccount',message:'mapped products',data:{mappedCount:mappedProducts.length},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H2'})}).catch(()=>{});
    // #endregion

    // 4. upsertProductsForAccount aufrufen
    let result;
    try {
      result = await upsertProductsForAccount(accountId, mappedProducts);
    } catch (dbError) {
      // Datenbank-Fehler: Collection oder Attribute fehlen
      console.error("Datenbank-Fehler beim Speichern:", dbError);
      
      // Prüfe auf spezifische Datenbank-Fehler
      if (dbError.code === 404 || dbError.type === 'collection_not_found') {
        throw new Error("Datenbank-Fehler: Products-Collection existiert nicht. Bitte Datenbank-Schema einrichten.");
      }
      if (dbError.code === 400 || dbError.message?.includes('attribute')) {
        throw new Error(`Datenbank-Fehler: Ein Attribut fehlt oder ist ungültig. Details: ${dbError.message}`);
      }
      if (dbError.code === 401 || dbError.type === 'permission_denied') {
        throw new Error("Datenbank-Fehler: Keine Berechtigung zum Speichern von Produkten. Bitte Berechtigungen prüfen.");
      }
      
      // Generischer Datenbank-Fehler
      throw new Error(`Datenbank-Fehler beim Speichern: ${dbError.message || "Unbekannter Fehler"}`);
    }

    // 5. account_last_scan_at aktualisieren
    try {
      await updateAccountLastScanAt(accountId, new Date().toISOString());
    } catch (updateError) {
      // Nicht kritisch, nur loggen
      console.warn("Fehler beim Aktualisieren von account_last_scan_at:", updateError);
    }

    // 6. Return { created, updated }
    return result;
  } catch (e) {
    console.error("Fehler beim Scannen der Produkte:", e);
    throw e;
  }
}

/**
 * Erstellt oder aktualisiert Produkte für einen Account (vorbereitet für Extension-Scans)
 * @param {string} accountId - ID des Accounts
 * @param {Array<Object>} products - Array von Produkt-Daten (kann partiell sein)
 * @returns {Promise<{ created: number, updated: number }>} Anzahl erstellter/aktualisierter Produkte
 */
export async function upsertProductsForAccount(accountId, products) {
  if (!accountId) {
    throw new Error("accountId ist erforderlich");
  }
  if (!Array.isArray(products) || products.length === 0) {
    return { created: 0, updated: 0 };
  }

  try {
    // Lade Account, um Market und andere Daten abzuleiten
    const account = await getAccountById(accountId);
    if (!account) {
      throw new Error("Account nicht gefunden");
    }

    // Leite Market und Currency aus Account ab
    const market = deriveMarketFromAccount(account);
    if (market === "UNKNOWN") {
      throw new Error(
        "Market konnte nicht erkannt werden. Bitte Account refreshen."
      );
    }

      const currency = deriveCurrencyFromMarket(market);
      const platform = "ebay"; // Enum-Werte sind lowercase gemäß Fehlermeldung: [amazon], [ebay]

    // Lade alle bestehenden Produkte (paginiert, Appwrite max 100/Request)
    const existingProducts = await fetchAllProductsByAccount(accountId);
    // #region agent log
    fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'productsService.js:upsertProductsForAccount',message:'existing products loaded',data:{productsToUpsert:products.length,existingCount:existingProducts.length},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
    // #endregion

    // Erstelle Map von platform_product_id -> bestehendes Produkt
    const existingProductsMap = new Map();
    existingProducts.forEach((p) => {
      if (p.product_platform_product_id) {
        existingProductsMap.set(p.product_platform_product_id, p);
      }
    });

    let created = 0;
    let updated = 0;

    // Verarbeite jedes Produkt
    for (const productData of products) {
      // Validiere, dass platform_product_id vorhanden ist
      if (!productData.product_platform_product_id) {
        console.warn("Produkt ohne product_platform_product_id übersprungen:", productData);
        continue;
      }

      const platformProductId = productData.product_platform_product_id;
      const existingProduct = existingProductsMap.get(platformProductId);

      // Ergänze fehlende erforderliche Felder aus Account
      const fullProductData = {
        product_account_id: accountId,
        product_platform: platform,
        product_platform_market: market,
        product_currency: currency,
        ...productData, // Produkt-Daten überschreiben Account-Daten wo vorhanden
      };

      try {
        if (existingProduct) {
          // Aktualisiere bestehendes Produkt
          await databases.updateDocument(
            databaseId,
            productsCollectionId,
            existingProduct.$id,
            fullProductData
          );
          updated++;
        } else {
          // Erstelle neues Produkt (product_first_fullscan_at = heutiges Datum)
          await databases.createDocument(
            databaseId,
            productsCollectionId,
            ID.unique(),
            {
              ...fullProductData,
              product_first_fullscan_at: new Date().toISOString()
            }
          );
          created++;
        }
      } catch (e) {
        console.error(`Fehler beim Upsert des Produkts "${platformProductId}":`, e);
        // #region agent log
        fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'productsService.js:upsertProductsForAccount',message:'upsert error',data:{platformProductId,code:e?.code,type:e?.type,message:String(e?.message||'')},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H3'})}).catch(()=>{});
        // #endregion
        // Prüfe auf spezifische Datenbank-Fehler
        if (e.code === 404 || e.type === 'collection_not_found' || e.type === 'document_not_found') {
          throw new Error("Datenbank-Fehler: Products-Collection oder Dokument existiert nicht. Bitte Datenbank-Schema einrichten.");
        }
        if (e.code === 400 || e.message?.includes('attribute') || e.message?.includes('required')) {
          throw new Error(`Datenbank-Fehler: Ein Attribut fehlt oder ist ungültig. Produkt: ${platformProductId}, Details: ${e.message}`);
        }
        if (e.code === 401 || e.type === 'permission_denied') {
          throw new Error("Datenbank-Fehler: Keine Berechtigung zum Speichern von Produkten. Bitte Berechtigungen prüfen.");
        }
        
        // Bei anderen Fehlern: Weiter mit nächstem Produkt (nicht kritisch)
        console.warn(`Überspringe Produkt "${platformProductId}" aufgrund von Fehler:`, e.message);
        continue;
      }
    }

    // #region agent log
    fetch('http://127.0.0.1:7242/ingest/246fe132-ecc5-435f-bd9c-fe5e8e26089d',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'productsService.js:upsertProductsForAccount',message:'upsert result',data:{created,updated},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'H1'})}).catch(()=>{});
    // #endregion
    return { created, updated };
  } catch (e) {
    console.error("Fehler beim Upsert der Produkte:", e);
    throw e;
  }
}
