import prisma from "../db.server";
import { logger } from "../lib/security/logger";
import { BillingService } from "./billing.server";
import { assertTenantScope } from "../lib/security/tenant-context";

export type StoreCategory =
  | "fashion"
  | "beauty"
  | "electronics"
  | "home"
  | "furniture"
  | "food"
  | "jewelry"
  | "sports"
  | "pets"
  | "automotive"
  | "baby"
  | "toys"
  | "books"
  | "digital_products"
  | "general_retail"
  | "other"
  | "unknown";

export interface PriceRange {
  min: number;
  max: number;
}

export interface StoreProfileRecord {
  id: string;
  shopId: string;
  category: StoreCategory;
  categoryConfidence: number;
  businessType: string;
  productTypes: string[];
  targetAudience: string;
  brandTone: string;
  currency: string;
  priceRange: PriceRange;
  languages: string[];
  country: string | null;
  capabilities: string[];
  metadata?: Record<string, any>;
  lastAnalyzedAt: Date;
}

export interface ThemeContextRecord {
  id: string;
  shopId: string;
  themeName: string | null;
  visualStyle: string | null;
  navigationCategories: string[];
  featuredCollections: string[];
  homepageSections: string[];
  brandPresentation: string | null;
  storefrontLanguage: string;
  storefrontContent?: Record<string, any>;
  lastAnalyzedAt: Date;
}

export interface StoreIntelligenceResult {
  profile: StoreProfileRecord;
  theme: ThemeContextRecord;
}

// Category keyword lexicons for evidence-based classification
const CATEGORY_LEXICONS: Record<StoreCategory, string[]> = {
  fashion: [
    "clothing", "apparel", "dress", "shirt", "t-shirt", "tee", "pant", "pants", "jeans",
    "jacket", "coat", "hoodie", "sweater", "cardigan", "skirt", "blouse", "suit", "blazer",
    "footwear", "shoes", "sneakers", "boots", "sandals", "heels", "hat", "cap", "scarf",
    "socks", "lingerie", "swimwear", "activewear", "outerwear", "denim", "cotton", "silk",
    "linen", "leather", "wool", "casual", "formal", "vintage", "streetwear", "couture",
  ],
  beauty: [
    "beauty", "cosmetics", "skincare", "makeup", "serum", "lotion", "moisturizer", "cream",
    "cleanser", "toner", "sunscreen", "lipstick", "lip", "mascara", "foundation", "eyeliner",
    "fragrance", "perfume", "cologne", "haircare", "shampoo", "conditioner", "hair", "body",
    "scrub", "facial", "organic", "vegan", "dermatologist", "anti-aging", "glow", "skin",
  ],
  electronics: [
    "electronics", "gadget", "phone", "smartphone", "laptop", "computer", "pc", "tablet",
    "headphone", "earbuds", "audio", "speaker", "bluetooth", "charger", "cable", "adapter",
    "camera", "lens", "drone", "smartwatch", "gaming", "console", "keyboard", "mouse",
    "monitor", "tv", "oled", "led", "wireless", "usb", "battery", "power bank", "tech",
  ],
  home: [
    "home", "decor", "kitchen", "cookware", "pan", "pot", "utensil", "knife", "bedding",
    "sheet", "pillow", "blanket", "comforter", "duvet", "curtain", "rug", "carpet", "lighting",
    "lamp", "candle", "vase", "clock", "bath", "towel", "storage", "organizer", "garden",
    "plant", "planter", "dining", "tableware", "plate", "glassware", "mug",
  ],
  furniture: [
    "furniture", "sofa", "couch", "chair", "armchair", "table", "desk", "coffee table",
    "dining table", "bed", "mattress", "headboard", "nightstand", "dresser", "wardrobe",
    "cabinet", "bookshelf", "shelf", "ottoman", "bench", "stool", "patio", "wood", "oak",
    "walnut", "teak", "modular", "ergonomic",
  ],
  food: [
    "food", "beverage", "snack", "coffee", "tea", "chocolate", "candy", "sweet", "spice",
    "sauce", "oil", "pasta", "bakery", "bread", "cake", "cookie", "organic", "gourmet",
    "artisan", "vegan", "keto", "gluten-free", "drink", "juice", "wine", "beer", "grocery",
    "nut", "seed", "honey", "jam", "syrup",
  ],
  jewelry: [
    "jewelry", "jewellery", "ring", "necklace", "bracelet", "earring", "pendant", "chain",
    "diamond", "gold", "silver", "platinum", "gemstone", "pearl", "emerald", "ruby", "sapphire",
    "wedding", "engagement", "luxury", "fine jewelry", "charm", "bangle", "cufflink",
  ],
  sports: [
    "sports", "fitness", "gym", "workout", "exercise", "yoga", "mat", "dumbbell", "weights",
    "running", "hiking", "cycling", "bicycle", "outdoor", "camping", "tent", "backpack",
    "swimming", "football", "basketball", "tennis", "golf", "athletic", "jersey", "protein",
    "supplement", "recovery",
  ],
  pets: [
    "pet", "pets", "dog", "puppy", "cat", "kitten", "bird", "fish", "aquarium", "collar",
    "leash", "harness", "pet food", "kibble", "treats", "pet bed", "crate", "pet toy",
    "grooming", "litter", "scratching post", "flea", "veterinary",
  ],
  automotive: [
    "automotive", "car", "auto", "vehicle", "motorcycle", "bike", "parts", "accessory",
    "tire", "wheel", "oil", "filter", "brake", "headlight", "seat cover", "mat", "dash",
    "wiper", "cleaner", "wax", "tool", "garage", "mechanic",
  ],
  baby: [
    "baby", "infant", "toddler", "newborn", "diaper", "wipes", "stroller", "pram", "crib",
    "car seat", "pacifier", "bottle", "nursery", "onesie", "bib", "teether", "baby carrier",
    "maternity", "nursing", "breastfeeding",
  ],
  toys: [
    "toy", "toys", "game", "games", "puzzle", "doll", "action figure", "lego", "building blocks",
    "board game", "card game", "educational toy", "plush", "stuffed animal", "rc car",
    "craft", "play", "kids",
  ],
  books: [
    "book", "books", "novel", "fiction", "non-fiction", "biography", "paperback", "hardcover",
    "ebook", "audiobook", "journal", "notebook", "planner", "stationery", "pen", "art supplies",
    "magazine", "comic", "manga",
  ],
  digital_products: [
    "digital", "download", "template", "software", "preset", "course", "ebook", "printable",
    "svg", "font", "audio file", "sample pack", "theme", "plugin", "license", "membership",
    "subscription", "digital guide",
  ],
  general_retail: [],
  other: [],
  unknown: [],
};

function tokenize(text: string): string[] {
  return (text || "")
    .toLowerCase()
    .replace(/[^\w\s-]/g, " ")
    .split(/\s+/)
    .filter((w) => w.length > 2);
}

export function classifyStoreCategory(products: Array<{
  title?: string;
  description?: string | null;
  tags?: any;
  productType?: string | null;
  vendor?: string | null;
}>): {
  category: StoreCategory;
  confidence: number;
  productTypes: string[];
  dominantVendors: string[];
} {
  if (!products || products.length === 0) {
    return {
      category: "unknown",
      confidence: 0.0,
      productTypes: [],
      dominantVendors: [],
    };
  }

  const scores: Record<StoreCategory, number> = {
    fashion: 0,
    beauty: 0,
    electronics: 0,
    home: 0,
    furniture: 0,
    food: 0,
    jewelry: 0,
    sports: 0,
    pets: 0,
    automotive: 0,
    baby: 0,
    toys: 0,
    books: 0,
    digital_products: 0,
    general_retail: 0,
    other: 0,
    unknown: 0,
  };

  const productTypeSet = new Set<string>();
  const vendorCounts: Record<string, number> = {};
  let totalMatchedSignals = 0;

  for (const p of products) {
    const titleTokens = tokenize(p.title || "");
    const descTokens = tokenize((p.description || "").slice(0, 300));
    const typeTokens = tokenize(p.productType || "");
    
    if (p.productType && p.productType.trim()) {
      productTypeSet.add(p.productType.trim());
    }

    if (p.vendor && p.vendor.trim()) {
      vendorCounts[p.vendor.trim()] = (vendorCounts[p.vendor.trim()] || 0) + 1;
    }

    let tagTokens: string[] = [];
    if (Array.isArray(p.tags)) {
      tagTokens = p.tags.flatMap((t: any) => tokenize(String(t)));
    } else if (typeof p.tags === "string") {
      tagTokens = tokenize(p.tags);
    }

    const weightedTokens = [
      ...titleTokens,
      ...titleTokens,
      ...typeTokens,
      ...typeTokens,
      ...typeTokens,
      ...tagTokens,
      ...tagTokens,
      ...descTokens,
    ];

    for (const token of weightedTokens) {
      for (const [cat, keywords] of Object.entries(CATEGORY_LEXICONS)) {
        if (cat === "general_retail" || cat === "other" || cat === "unknown") continue;
        if (keywords.some((kw) => kw === token || (kw.length > 4 && token.includes(kw)))) {
          scores[cat as StoreCategory] += 1;
          totalMatchedSignals += 1;
        }
      }
    }
  }

  let dominantCat: StoreCategory = "unknown";
  let maxScore = 0;

  for (const [cat, score] of Object.entries(scores)) {
    if (score > maxScore) {
      maxScore = score;
      dominantCat = cat as StoreCategory;
    }
  }

  const confidence = totalMatchedSignals > 0
    ? Math.min(0.99, Math.round((maxScore / totalMatchedSignals) * 100) / 100)
    : 0.0;

  if (confidence < 0.25 || maxScore < 2) {
    dominantCat = products.length > 5 ? "general_retail" : "unknown";
  }

  const dominantVendors = Object.entries(vendorCounts)
    .sort((a, b) => b[1] - a[1])
    .slice(0, 5)
    .map(([v]) => v);

  return {
    category: dominantCat,
    confidence: dominantCat === "unknown" ? Math.min(confidence, 0.3) : confidence,
    productTypes: Array.from(productTypeSet).slice(0, 15),
    dominantVendors,
  };
}

function inferStorePersona(category: StoreCategory, productTypes: string[], currency: string): {
  businessType: string;
  targetAudience: string;
  brandTone: string;
} {
  switch (category) {
    case "fashion":
      return {
        businessType: "online apparel & fashion retailer",
        targetAudience: "style-conscious shoppers and trendsetters",
        brandTone: "chic, friendly, and trend-forward",
      };
    case "beauty":
      return {
        businessType: "skincare, cosmetics & wellness boutique",
        targetAudience: "beauty, skincare, and self-care enthusiasts",
        brandTone: "warm, uplifting, and knowledgeable",
      };
    case "electronics":
      return {
        businessType: "consumer electronics & tech gear merchant",
        targetAudience: "tech enthusiasts, professionals, and gamers",
        brandTone: "precise, knowledgeable, and helpful",
      };
    case "home":
    case "furniture":
      return {
        businessType: "home goods, decor & furniture store",
        targetAudience: "homeowners, renters, and interior design enthusiasts",
        brandTone: "warm, welcoming, and inspiring",
      };
    case "food":
      return {
        businessType: "specialty food, gourmet treats & beverage store",
        targetAudience: "food lovers, culinary enthusiasts, and health-conscious consumers",
        brandTone: "inviting, appetizing, and friendly",
      };
    case "jewelry":
      return {
        businessType: "fine jewelry & luxury accessories boutique",
        targetAudience: "gift buyers, luxury shoppers, and jewelry collectors",
        brandTone: "sophisticated, elegant, and attentive",
      };
    case "sports":
      return {
        businessType: "sports, athletic equipment & activewear store",
        targetAudience: "athletes, fitness enthusiasts, and outdoor adventurers",
        brandTone: "energetic, motivational, and practical",
      };
    case "pets":
      return {
        businessType: "pet supplies, food & pet care store",
        targetAudience: "loving pet parents and animal owners",
        brandTone: "playful, caring, and trustworthy",
      };
    case "baby":
    case "toys":
      return {
        businessType: "baby, children's essentials & toy store",
        targetAudience: "parents, families, and gift shoppers",
        brandTone: "nurturing, playful, and reassuring",
      };
    case "books":
      return {
        businessType: "books, stationery & literature merchant",
        targetAudience: "readers, learners, and stationery enthusiasts",
        brandTone: "thoughtful, engaging, and articulate",
      };
    case "digital_products":
      return {
        businessType: "digital downloads & software store",
        targetAudience: "creators, professionals, and digital consumers",
        brandTone: "direct, modern, and efficient",
      };
    case "automotive":
      return {
        businessType: "auto parts, vehicle accessories & garage store",
        targetAudience: "car owners, mechanics, and automotive enthusiasts",
        brandTone: "practical, robust, and reliable",
      };
    default:
      return {
        businessType: "online retail store",
        targetAudience: "general store customers",
        brandTone: "friendly, helpful, and courteous",
      };
  }
}

export class StoreIntelligenceService {
  static async analyzeStoreAndBuildProfile(
    shopId: string,
    shopifyDomain: string
  ): Promise<StoreIntelligenceResult> {
    
    logger.info("Starting Store Intelligence Discovery", { shopId, shopifyDomain });

    const shop = await prisma.shop.findUnique({
      where: { id: shopId },
      include: {
        chatbotSettings: true,
        productCaches: { take: 100 },
        articleCaches: { take: 20 },
        knowledgeBase: { take: 20 },
      },
    });

    if (!shop) {
      throw new Error(`Shop not found for Store Intelligence: ${shopId}`);
    }

    assertTenantScope(shop.id, shopId);

    const products = shop.productCaches || [];
    let minPrice = Infinity;
    let maxPrice = 0;
    let detectedCurrency = "USD";

    for (const p of products) {
      const pMin = parseFloat(p.minPrice.toString());
      const pMax = parseFloat(p.maxPrice.toString());
      if (!isNaN(pMin) && pMin < minPrice) minPrice = pMin;
      if (!isNaN(pMax) && pMax > maxPrice) maxPrice = pMax;
      if (p.currency) detectedCurrency = p.currency;
    }

    if (minPrice === Infinity) minPrice = 0;

    const classification = classifyStoreCategory(products);
    const persona = inferStorePersona(
      classification.category,
      classification.productTypes,
      detectedCurrency
    );

    const planInfo = await BillingService.getCurrentPlan(shopifyDomain);
    const plan = planInfo.plan;

    const capabilities: string[] = ["shopify.catalog_search", "shopify.product_details"];
    if (plan === "STARTER" || plan === "PRO" || plan === "GROWTH") {
      capabilities.push(
        "shopify.storefront_cart",
        "shopify.variant_selection",
        "shopify.checkout",
        "shopify.shipping_rates",
        "shopify.promo_codes",
        "shopify.customer_auth"
      );
    }
    if (plan === "PRO" || plan === "GROWTH") {
      capabilities.push(
        "ai.chatbot",
        "ai.recommendations",
        "ai.support",
        "ai.knowledge_base",
        "ai.byok_openai",
        "ai.byok_gemini",
        "ai.priority_throughput"
      );
    }

    const priceRangeData = {
      min: Math.round(minPrice * 100) / 100,
      max: Math.round(maxPrice * 100) / 100,
    };

    const storeLanguage = shop.chatbotSettings?.language || "en";

    const profile = await prisma.storeProfile.upsert({
      where: { shopId },
      update: {
        category: classification.category,
        categoryConfidence: classification.confidence,
        businessType: persona.businessType,
        productTypes: classification.productTypes,
        targetAudience: persona.targetAudience,
        brandTone: shop.chatbotSettings?.tone || persona.brandTone,
        currency: detectedCurrency,
        priceRange: priceRangeData,
        languages: [storeLanguage],
        capabilities,
        metadata: {
          analyzedProductsCount: products.length,
          dominantVendors: classification.dominantVendors,
          verifiedPlan: plan,
        },
        lastAnalyzedAt: new Date(),
      },
      create: {
        shopId,
        category: classification.category,
        categoryConfidence: classification.confidence,
        businessType: persona.businessType,
        productTypes: classification.productTypes,
        targetAudience: persona.targetAudience,
        brandTone: shop.chatbotSettings?.tone || persona.brandTone,
        currency: detectedCurrency,
        priceRange: priceRangeData,
        languages: [storeLanguage],
        capabilities,
        metadata: {
          analyzedProductsCount: products.length,
          dominantVendors: classification.dominantVendors,
          verifiedPlan: plan,
        },
        lastAnalyzedAt: new Date(),
      },
    });

    const navigationCategories = classification.productTypes.length > 0
      ? classification.productTypes
      : ["All Products", "New Arrivals", "Best Sellers"];

    const theme = await prisma.themeContext.upsert({
      where: { shopId },
      update: {
        themeName: "Shopify Dawn / Online Store 2.0",
        visualStyle: "clean, responsive e-commerce storefront",
        navigationCategories,
        featuredCollections: navigationCategories.slice(0, 5),
        homepageSections: ["Hero Banner", "Featured Collection", "Product Grid", "Store Policies", "Footer"],
        brandPresentation: `${shop.chatbotSettings?.botName || "Store Assistant"} on ${shopifyDomain}`,
        storefrontLanguage: storeLanguage,
        lastAnalyzedAt: new Date(),
      },
      create: {
        shopId,
        themeName: "Shopify Dawn / Online Store 2.0",
        visualStyle: "clean, responsive e-commerce storefront",
        navigationCategories,
        featuredCollections: navigationCategories.slice(0, 5),
        homepageSections: ["Hero Banner", "Featured Collection", "Product Grid", "Store Policies", "Footer"],
        brandPresentation: `${shop.chatbotSettings?.botName || "Store Assistant"} on ${shopifyDomain}`,
        storefrontLanguage: storeLanguage,
        lastAnalyzedAt: new Date(),
      },
    });

    logger.info("Store Intelligence Profile Updated", {
      shopId,
      category: profile.category,
      confidence: profile.categoryConfidence,
      businessType: profile.businessType,
    });

    return {
      profile: {
        id: profile.id,
        shopId: profile.shopId,
        category: profile.category as StoreCategory,
        categoryConfidence: profile.categoryConfidence,
        businessType: profile.businessType,
        productTypes: (profile.productTypes as string[]) || [],
        targetAudience: profile.targetAudience,
        brandTone: profile.brandTone,
        currency: profile.currency,
        priceRange: (profile.priceRange as any) || { min: 0, max: 0 },
        languages: (profile.languages as string[]) || ["en"],
        country: profile.country,
        capabilities: (profile.capabilities as string[]) || [],
        metadata: (profile.metadata as Record<string, any>) || {},
        lastAnalyzedAt: profile.lastAnalyzedAt,
      },
      theme: {
        id: theme.id,
        shopId: theme.shopId,
        themeName: theme.themeName,
        visualStyle: theme.visualStyle,
        navigationCategories: (theme.navigationCategories as string[]) || [],
        featuredCollections: (theme.featuredCollections as string[]) || [],
        homepageSections: (theme.homepageSections as string[]) || [],
        brandPresentation: theme.brandPresentation,
        storefrontLanguage: theme.storefrontLanguage,
        storefrontContent: (theme.storefrontContent as Record<string, any>) || {},
        lastAnalyzedAt: theme.lastAnalyzedAt,
      },
    };
  }

  static async getStoreProfile(
    shopId: string,
    shopifyDomain?: string
  ): Promise<StoreProfileRecord> {
    const existing = await prisma.storeProfile.findUnique({
      where: { shopId },
    });

    if (existing) {
      return {
        id: existing.id,
        shopId: existing.shopId,
        category: existing.category as StoreCategory,
        categoryConfidence: existing.categoryConfidence,
        businessType: existing.businessType,
        productTypes: (existing.productTypes as string[]) || [],
        targetAudience: existing.targetAudience,
        brandTone: existing.brandTone,
        currency: existing.currency,
        priceRange: (existing.priceRange as any) || { min: 0, max: 0 },
        languages: (existing.languages as string[]) || ["en"],
        country: existing.country,
        capabilities: (existing.capabilities as string[]) || [],
        metadata: (existing.metadata as Record<string, any>) || {},
        lastAnalyzedAt: existing.lastAnalyzedAt,
      };
    }

    const domain = shopifyDomain || (await prisma.shop.findUnique({ where: { id: shopId }, select: { shopifyDomain: true } }))?.shopifyDomain;
    if (domain) {
      const res = await this.analyzeStoreAndBuildProfile(shopId, domain);
      return res.profile;
    }

    return {
      id: `fallback_${shopId}`,
      shopId,
      category: "unknown",
      categoryConfidence: 0.0,
      businessType: "online retail store",
      productTypes: [],
      targetAudience: "general store customers",
      brandTone: "friendly and helpful",
      currency: "USD",
      priceRange: { min: 0, max: 0 },
      languages: ["en"],
      country: null,
      capabilities: ["shopify.catalog_search", "shopify.product_details"],
      lastAnalyzedAt: new Date(),
    };
  }

  static async getThemeContext(
    shopId: string,
    shopifyDomain?: string
  ): Promise<ThemeContextRecord> {
    const existing = await prisma.themeContext.findUnique({
      where: { shopId },
    });

    if (existing) {
      return {
        id: existing.id,
        shopId: existing.shopId,
        themeName: existing.themeName,
        visualStyle: existing.visualStyle,
        navigationCategories: (existing.navigationCategories as string[]) || [],
        featuredCollections: (existing.featuredCollections as string[]) || [],
        homepageSections: (existing.homepageSections as string[]) || [],
        brandPresentation: existing.brandPresentation,
        storefrontLanguage: existing.storefrontLanguage,
        storefrontContent: (existing.storefrontContent as Record<string, any>) || {},
        lastAnalyzedAt: existing.lastAnalyzedAt,
      };
    }

    const domain = shopifyDomain || (await prisma.shop.findUnique({ where: { id: shopId }, select: { shopifyDomain: true } }))?.shopifyDomain;
    if (domain) {
      const res = await this.analyzeStoreAndBuildProfile(shopId, domain);
      return res.theme;
    }

    return {
      id: `fallback_${shopId}`,
      shopId,
      themeName: "Shopify Standard Theme",
      visualStyle: "clean e-commerce",
      navigationCategories: ["Products"],
      featuredCollections: ["All Products"],
      homepageSections: ["Featured Products"],
      brandPresentation: "Online Store",
      storefrontLanguage: "en",
      lastAnalyzedAt: new Date(),
    };
  }

  static async syncStoreIntelligence(shopifyDomain: string): Promise<StoreIntelligenceResult> {
    const shop = await prisma.shop.findUnique({
      where: { shopifyDomain: shopifyDomain.toLowerCase().trim() },
      select: { id: true, shopifyDomain: true },
    });

    if (!shop) {
      throw new Error(`Cannot sync store intelligence: store ${shopifyDomain} not found`);
    }

    return this.analyzeStoreAndBuildProfile(shop.id, shop.shopifyDomain);
  }
}
