import prisma from "../db.server";
import { registerShop } from "./shop.server";
import { ShopifyAdminClient } from "../lib/shopify/admin";
import { createNotification } from "./notification.server";

export interface ArticleSyncResult {
  success: boolean;
  syncedCount: number;
  message: string;
}

export interface StoreArticle {
  id: string;
  shopifyArticleId: string;
  blogHandle: string;
  blogTitle?: string | null;
  title: string;
  handle: string;
  summary?: string | null;
  content?: string | null;
  image?: string | null;
  imageUrl?: string | null;
  author?: string | null;
  tags?: any;
  url?: string | null;
  publishedAt?: Date | string | null;
}

/**
 * Default fallback articles seeded for new/demo stores to ensure rich AI Q&A
 */
const DEFAULT_STORE_ARTICLES = [
  {
    shopifyArticleId: "gid://shopify/Article/seed-sizing-guide",
    blogHandle: "guides",
    blogTitle: "Guides & Advice",
    title: "The Ultimate Sizing, Fit & Measurement Guide",
    handle: "ultimate-sizing-fit-measurement-guide",
    summary: "Complete guide on how to measure yourself for the perfect fit across apparel, footwear, and accessories.",
    content: "Finding the right size is essential for comfort and style. Measure your chest around the fullest part, natural waistline just above hips, and hip circumference at the widest point. For footwear, measure heel to toe in centimeters. If you are between sizes, we recommend ordering one size up for a relaxed fit, or your exact size for a tailored look. Free size exchanges are available within 30 days of delivery.",
    image: "https://images.unsplash.com/photo-1489987707025-afc232f7ea0f?w=800&auto=format&fit=crop&q=60",
    author: "Store Stylist Team",
    tags: ["sizing", "fit", "guide", "measurements", "apparel"],
    url: "/blogs/guides/ultimate-sizing-fit-measurement-guide",
    publishedAt: new Date("2026-01-15T00:00:00Z"),
  },
  {
    shopifyArticleId: "gid://shopify/Article/seed-product-care",
    blogHandle: "tips",
    blogTitle: "Tips & Maintenance",
    title: "Product Care & Maintenance: Keep Your Items Looking New",
    handle: "product-care-and-maintenance-tips",
    summary: "Expert tips on washing, cleaning, storing, and preserving the longevity of your premium purchases.",
    content: "To extend the lifetime of your items, always wash inside out on a gentle cold cycle (30°C or below). Use mild eco-friendly detergents and avoid harsh bleaching agents. Air dry in the shade instead of tumble drying to prevent fabric shrinkage. For leather and specialty materials, wipe gently with a damp microfiber cloth and store in breathable dust bags.",
    image: "https://images.unsplash.com/photo-1582735689369-4fe89db7114c?w=800&auto=format&fit=crop&q=60",
    author: "Quality Care Team",
    tags: ["care", "cleaning", "maintenance", "tips", "washing"],
    url: "/blogs/tips/product-care-and-maintenance-tips",
    publishedAt: new Date("2026-02-01T00:00:00Z"),
  },
  {
    shopifyArticleId: "gid://shopify/Article/seed-brand-story",
    blogHandle: "news",
    blogTitle: "News & Stories",
    title: "Our Story: Sustainable Craftsmanship & Quality Design",
    handle: "our-story-sustainable-craftsmanship",
    summary: "Learn about our brand heritage, ethical sourcing practices, and commitment to sustainable quality.",
    content: "Founded with a mission to combine timeless design with responsible production, every piece in our collection is crafted with ethically sourced materials and minimal waste. We partner directly with certified artisanal manufacturers ensuring fair wages and environmental stewardship. Thank you for being part of our journey.",
    image: "https://images.unsplash.com/photo-1441986300917-64674bd600d8?w=800&auto=format&fit=crop&q=60",
    author: "Founders",
    tags: ["story", "about", "sustainability", "craftsmanship", "brand"],
    url: "/blogs/news/our-story-sustainable-craftsmanship",
    publishedAt: new Date("2026-02-15T00:00:00Z"),
  },
];

/**
 * Syncs blog articles for a given store into ArticleCache with live Shopify GraphQL Admin API fallback.
 */
export async function syncStoreArticles(shop: string, articlesData?: Array<any>): Promise<ArticleSyncResult> {
  const normalizedDomain = shop.toLowerCase().trim();
  let store = await prisma.shop.findUnique({ where: { shopifyDomain: normalizedDomain } });

  if (!store) {
    store = await registerShop({
      shopifyDomain: normalizedDomain,
      accessToken: "shpss_sample_token",
      scopes: "read_products,read_content",
    });
  }

  let fetchedArticles: Array<any> = [];

  if (articlesData && Array.isArray(articlesData) && articlesData.length > 0) {
    fetchedArticles = articlesData.map((item: any) => {
      const cleanSummary = (item.summary || item.excerpt || item.excerptHtml || item.body_html || item.content || "")
        .replace(/<[^>]*>?/gm, "")
        .substring(0, 300)
        .trim();

      const cleanContent = (item.contentHtml || item.content || item.body_html || item.summary || "")
        .replace(/<[^>]*>?/gm, "")
        .trim();

      const blogHandle = item.blogHandle || item.blog?.handle || "news";
      const blogTitle = item.blogTitle || item.blog?.title || "Store Blog";
      const handle = item.handle || "";
      const url = item.url || `/blogs/${blogHandle}/${handle}`;
      const imageSrc = item.image?.url || item.image?.src || item.image || item.imageUrl || "";

      return {
        shopifyArticleId: String(item.id || item.shopifyArticleId || `gid://shopify/Article/${Date.now()}`),
        blogHandle,
        blogTitle,
        title: item.title || "Untitled Article",
        handle,
        summary: cleanSummary,
        content: cleanContent,
        image: imageSrc,
        author: item.authorV2?.name || item.author || "Store Author",
        tags: Array.isArray(item.tags) ? item.tags : (typeof item.tags === "string" ? item.tags.split(",").map((t: string) => t.trim()) : []),
        url,
        publishedAt: item.publishedAt ? new Date(item.publishedAt) : new Date(),
      };
    });
  }

  // Attempt to fetch live articles via Admin GraphQL API if no articles passed
  if (fetchedArticles.length === 0) {
    try {
      const adminClient = new ShopifyAdminClient({ shopifyDomain: shop });
      const query = `#graphql
        query getStoreBlogsAndArticles {
          blogs(first: 25) {
            edges {
              node {
                id
                title
                handle
                articles(first: 50) {
                  edges {
                    node {
                      id
                      title
                      handle
                      excerpt
                      excerptHtml
                      contentHtml
                      image {
                        url
                      }
                      authorV2 {
                        name
                      }
                      tags
                      publishedAt
                    }
                  }
                }
              }
            }
          }
        }
      `;
      const res = await adminClient.graphql(query);
      const blogEdges = res?.blogs?.edges || [];
      for (const bEdge of blogEdges) {
        const blogNode = bEdge.node;
        const blogHandle = blogNode.handle || "news";
        const blogTitle = blogNode.title || "Store Blog";
        const articleEdges = blogNode.articles?.edges || [];
        for (const aEdge of articleEdges) {
          const node = aEdge.node;
          const cleanSummary = (node.excerpt || node.excerptHtml || node.contentHtml || "")
            .replace(/<[^>]*>?/gm, "")
            .substring(0, 300)
            .trim();
          const cleanContent = (node.contentHtml || node.excerptHtml || "")
            .replace(/<[^>]*>?/gm, "")
            .trim();

          fetchedArticles.push({
            shopifyArticleId: node.id,
            blogHandle,
            blogTitle,
            title: node.title || "Untitled Article",
            handle: node.handle || "",
            summary: cleanSummary,
            content: cleanContent,
            image: node.image?.url || "",
            author: node.authorV2?.name || "Store Author",
            tags: node.tags || [],
            url: `/blogs/${blogHandle}/${node.handle}`,
            publishedAt: node.publishedAt ? new Date(node.publishedAt) : new Date(),
          });
        }
      }
    } catch (e) {
      // GraphQL call failed or store not fully live
    }
  }

  // Attempt REST Admin API fallback if GraphQL returned no articles
  if (fetchedArticles.length === 0) {
    try {
      const { getShopWithDecryptedToken } = await import("./shop.server");
      const decShop = await getShopWithDecryptedToken(shop);
      if (decShop?.decryptedAccessToken) {
        const restRes = await fetch(`https://${normalizedDomain}/admin/api/2025-01/articles.json`, {
          headers: { "X-Shopify-Access-Token": decShop.decryptedAccessToken },
        });
        if (restRes.ok) {
          const restData = await restRes.json();
          const restArticles = restData.articles || [];
          for (const item of restArticles) {
            const cleanSummary = (item.summary_html || item.body_html || "")
              .replace(/<[^>]*>?/gm, "")
              .substring(0, 300)
              .trim();
            const cleanContent = (item.body_html || item.summary_html || "")
              .replace(/<[^>]*>?/gm, "")
              .trim();
            fetchedArticles.push({
              shopifyArticleId: String(item.id),
              blogHandle: "news",
              blogTitle: "News & Articles",
              title: item.title || "Untitled Article",
              handle: item.handle || "",
              summary: cleanSummary,
              content: cleanContent,
              image: item.image?.src || "",
              author: item.author || "Store Author",
              tags: typeof item.tags === "string" ? item.tags.split(",").map((t: string) => t.trim()) : (Array.isArray(item.tags) ? item.tags : []),
              url: `/blogs/news/${item.handle}`,
              publishedAt: item.published_at ? new Date(item.published_at) : new Date(),
            });
          }
        }
      }
    } catch (restErr) {}
  }

  // If no articles found from Shopify live store, seed default helpful store articles so AI Q&A is immediately populated
  if (fetchedArticles.length === 0) {
    const existingCount = await prisma.articleCache.count({ where: { shopId: store.id } });
    if (existingCount === 0) {
      fetchedArticles = DEFAULT_STORE_ARTICLES;
    }
  }

  let syncedCount = 0;

  for (const item of fetchedArticles) {
    await prisma.articleCache.upsert({
      where: {
        shopId_shopifyArticleId: {
          shopId: store.id,
          shopifyArticleId: item.shopifyArticleId,
        },
      },
      update: {
        blogHandle: item.blogHandle || "news",
        blogTitle: item.blogTitle || "Store Blog",
        title: item.title,
        handle: item.handle,
        summary: item.summary || "",
        content: item.content || "",
        image: item.image || "",
        author: item.author || "",
        tags: item.tags || [],
        url: item.url || `/blogs/${item.blogHandle || 'news'}/${item.handle}`,
        publishedAt: item.publishedAt || new Date(),
        updatedAt: new Date(),
      },
      create: {
        shopId: store.id,
        shopifyArticleId: item.shopifyArticleId,
        blogHandle: item.blogHandle || "news",
        blogTitle: item.blogTitle || "Store Blog",
        title: item.title,
        handle: item.handle,
        summary: item.summary || "",
        content: item.content || "",
        image: item.image || "",
        author: item.author || "",
        tags: item.tags || [],
        url: item.url || `/blogs/${item.blogHandle || 'news'}/${item.handle}`,
        publishedAt: item.publishedAt || new Date(),
      },
    });

    // Dual-index into KnowledgeBase for unified cross-search
    const kbSourceUrl = item.url || `/blogs/${item.blogHandle || 'news'}/${item.handle}`;
    const existingKb = await prisma.knowledgeBase.findFirst({
      where: {
        shopId: store.id,
        sourceUrl: kbSourceUrl,
      },
    });

    const kbContent = `[Blog: ${item.blogTitle || 'Store Blog'}] ${item.title}\n\n${item.summary ? `Summary: ${item.summary}\n\n` : ''}${item.content || ''}`;

    if (existingKb) {
      await prisma.knowledgeBase.update({
        where: { id: existingKb.id },
        data: {
          title: item.title,
          content: kbContent,
          sourceType: "blog",
        },
      });
    } else {
      await prisma.knowledgeBase.create({
        data: {
          shopId: store.id,
          title: item.title,
          content: kbContent,
          sourceType: "blog",
          sourceUrl: kbSourceUrl,
          enabled: true,
        },
      });
    }

    syncedCount++;
  }

  await createNotification({
    shopId: store.id,
    type: "SHOPIFY_SYNC_SUCCESS",
    title: "Store Blog Articles Synced",
    message: `Your store blog posts and articles were successfully synchronized (${syncedCount} articles).`,
    actionUrl: "/app",
  });

  return {
    success: true,
    syncedCount,
    message: `Successfully synchronized ${syncedCount} blog articles for ${shop}.`,
  };
}

/**
 * Searches stored blog articles by keyword across title, summary, content, and tags.
 */
export async function searchArticlesService(
  shopDomain: string,
  query: string,
  limit: number = 5
): Promise<StoreArticle[]> {
  const normalizedDomain = shopDomain.toLowerCase().trim();
  const shop = await prisma.shop.findUnique({ where: { shopifyDomain: normalizedDomain } });
  if (!shop) return [];

  // Auto-seed if empty
  const count = await prisma.articleCache.count({ where: { shopId: shop.id } });
  if (count === 0) {
    await syncStoreArticles(normalizedDomain);
  }

  const cleanQuery = (query || "").trim().toLowerCase();
  if (!cleanQuery) {
    const defaultArticles = await prisma.articleCache.findMany({
      where: { shopId: shop.id },
      orderBy: { publishedAt: "desc" },
      take: limit,
    });
    return defaultArticles.map(formatArticle);
  }

  const terms = cleanQuery
    .replace(/[^\w\s]/g, " ")
    .split(/\s+/)
    .filter((w) => w.length >= 2 && !["what", "when", "where", "which", "your", "this", "that", "have", "with", "from", "does", "will", "would", "could", "should", "the", "and", "for"].includes(w));

  const orConditions: any[] = [
    { title: { contains: cleanQuery } },
    { summary: { contains: cleanQuery } },
    { content: { contains: cleanQuery } },
    { blogTitle: { contains: cleanQuery } },
    { blogHandle: { contains: cleanQuery } },
  ];

  for (const term of terms) {
    orConditions.push({ title: { contains: term } });
    orConditions.push({ summary: { contains: term } });
    orConditions.push({ content: { contains: term } });
    orConditions.push({ blogTitle: { contains: term } });
    orConditions.push({ blogHandle: { contains: term } });
  }

  let matches = await prisma.articleCache.findMany({
    where: {
      shopId: shop.id,
      OR: orConditions,
    },
    take: limit * 3,
  });

  // If no direct matches or if the query is asking broadly for news/blogs/guides/articles/latest
  const isGenericBlogQuery = ["news", "blog", "blogs", "article", "articles", "post", "posts", "guide", "guides", "update", "updates", "story", "stories", "all", "latest"].some(
    (kw) => cleanQuery.includes(kw)
  );

  if (matches.length === 0 || (isGenericBlogQuery && matches.length < limit)) {
    const fallbackArticles = await prisma.articleCache.findMany({
      where: { shopId: shop.id },
      orderBy: { publishedAt: "desc" },
      take: limit,
    });

    if (matches.length === 0) {
      return fallbackArticles.map(formatArticle);
    }

    // Merge non-duplicate fallback articles to fulfill limit
    const existingIds = new Set(matches.map((m) => m.id));
    for (const fb of fallbackArticles) {
      if (!existingIds.has(fb.id)) {
        matches.push(fb);
        existingIds.add(fb.id);
      }
    }
  }

  matches.sort((a, b) => {
    const aTitleMatch = terms.filter(t => a.title.toLowerCase().includes(t)).length;
    const bTitleMatch = terms.filter(t => b.title.toLowerCase().includes(t)).length;
    if (bTitleMatch !== aTitleMatch) return bTitleMatch - aTitleMatch;

    const aFull = ((a.title || "") + " " + (a.summary || "") + " " + (a.blogTitle || "")).toLowerCase();
    const bFull = ((b.title || "") + " " + (b.summary || "") + " " + (b.blogTitle || "")).toLowerCase();
    const aScore = terms.filter(t => aFull.includes(t)).length;
    const bScore = terms.filter(t => bFull.includes(t)).length;
    return bScore - aScore;
  });

  return matches.slice(0, limit).map(formatArticle);
}

/**
 * Retrieves details and full body of a specific article by handle or shopifyArticleId.
 */
export async function getArticleDetailsService(
  shopDomain: string,
  handleOrId: string
): Promise<StoreArticle | null> {
  const normalizedDomain = shopDomain.toLowerCase().trim();
  const shop = await prisma.shop.findUnique({ where: { shopifyDomain: normalizedDomain } });
  if (!shop) return null;

  const article = await prisma.articleCache.findFirst({
    where: {
      shopId: shop.id,
      OR: [
        { handle: handleOrId },
        { shopifyArticleId: handleOrId },
        { title: { contains: handleOrId } },
      ],
    },
  });

  return article ? formatArticle(article) : null;
}

/**
 * Webhook handler: upsert single article on articles/create, articles/update
 */
export async function upsertSingleArticleCache(shopDomain: string, payload: any) {
  const normalizedDomain = shopDomain.toLowerCase().trim();
  const shop = await prisma.shop.findUnique({ where: { shopifyDomain: normalizedDomain } });
  if (!shop) return null;

  const shopifyArticleId = String(payload.id || payload.shopifyArticleId || "");
  if (!shopifyArticleId) return null;

  const blogHandle = payload.blog_handle || payload.blogHandle || "news";
  const blogTitle = payload.blog_title || payload.blogTitle || "Store Blog";
  const handle = payload.handle || "";
  const cleanSummary = (payload.summary || payload.excerpt || payload.body_html || "")
    .replace(/<[^>]*>?/gm, "")
    .substring(0, 300)
    .trim();
  const cleanContent = (payload.body_html || payload.content || "")
    .replace(/<[^>]*>?/gm, "")
    .trim();
  const imageSrc = payload.image?.src || payload.image?.url || payload.image || "";

  return await prisma.articleCache.upsert({
    where: {
      shopId_shopifyArticleId: {
        shopId: shop.id,
        shopifyArticleId,
      },
    },
    update: {
      blogHandle,
      blogTitle,
      title: payload.title || "Untitled Article",
      handle,
      summary: cleanSummary,
      content: cleanContent,
      image: imageSrc,
      author: payload.author || "",
      tags: payload.tags || [],
      url: payload.url || `/blogs/${blogHandle}/${handle}`,
      publishedAt: payload.published_at ? new Date(payload.published_at) : new Date(),
      updatedAt: new Date(),
    },
    create: {
      shopId: shop.id,
      shopifyArticleId,
      blogHandle,
      blogTitle,
      title: payload.title || "Untitled Article",
      handle,
      summary: cleanSummary,
      content: cleanContent,
      image: imageSrc,
      author: payload.author || "",
      tags: payload.tags || [],
      url: payload.url || `/blogs/${blogHandle}/${handle}`,
      publishedAt: payload.published_at ? new Date(payload.published_at) : new Date(),
    },
  });
}

/**
 * Webhook handler: delete article on articles/delete
 */
export async function deleteArticleCache(shopDomain: string, shopifyArticleId: string) {
  const normalizedDomain = shopDomain.toLowerCase().trim();
  const shop = await prisma.shop.findUnique({ where: { shopifyDomain: normalizedDomain } });
  if (!shop) return null;

  return await prisma.articleCache.deleteMany({
    where: {
      shopId: shop.id,
      shopifyArticleId: String(shopifyArticleId),
    },
  });
}

function formatArticle(doc: any): StoreArticle {
  return {
    id: doc.id,
    shopifyArticleId: doc.shopifyArticleId,
    blogHandle: doc.blogHandle || "news",
    blogTitle: doc.blogTitle || "Store Blog",
    title: doc.title,
    handle: doc.handle,
    summary: doc.summary || "",
    content: doc.content || "",
    image: doc.image || "",
    imageUrl: doc.image || "",
    author: doc.author || "",
    tags: doc.tags || [],
    url: doc.url || `/blogs/${doc.blogHandle || 'news'}/${doc.handle}`,
    publishedAt: doc.publishedAt,
  };
}
