/**
 * Blog data access layer using Convex database
 *
 * This module provides functions for fetching blog posts from Convex
 * with support for bilingual content (Arabic/English), pagination, filtering,
 * and related post suggestions.
 */

import { unstable_cache } from "next/cache";
import { convexQuery } from "./convex-client";
import type { BlogPost, BlogMetadata } from "./blog.types";

/**
 * Shape of a blog_posts document returned from Convex.
 * Uses camelCase field names matching the Convex schema.
 */
interface ConvexBlogPost {
  _id: string;
  _creationTime: number;
  slug: string;
  lang: string;
  title: string;
  excerpt: string;
  content: string;
  coverImage?: string;
  author: string;
  tags: string[];
  published: boolean;
  featured: boolean;
  featuredOrder?: number;
  metaTitle?: string;
  metaDescription?: string;
  metaKeywords?: string[];
  ogImage?: string;
  readingTimeMinutes?: number;
  date: string;
  publishedAt?: number;
  createdAt: number;
  updatedAt: number;
}

/**
 * Maps a Convex blog post document to the BlogPost interface (includes content)
 */
function mapConvexPostToInterface(doc: ConvexBlogPost): BlogPost {
  return {
    slug: doc.slug,
    title: doc.title,
    date: doc.date,
    excerpt: doc.excerpt,
    coverImage: doc.coverImage || undefined,
    tags: doc.tags || [],
    author: doc.author,
    published: doc.published,
    featured: doc.featured || false,
    content: doc.content,
    readingTime: doc.readingTimeMinutes
      ? `${doc.readingTimeMinutes}`
      : undefined,
    lang: doc.lang as "ar" | "en",
  };
}

/**
 * Maps a Convex blog post document to BlogMetadata (without content)
 */
function mapConvexPostToMetadata(doc: ConvexBlogPost): BlogMetadata {
  return {
    slug: doc.slug,
    title: doc.title,
    date: doc.date,
    excerpt: doc.excerpt,
    coverImage: doc.coverImage || undefined,
    tags: doc.tags || [],
    author: doc.author,
    published: doc.published,
    featured: doc.featured || false,
    readingTime: doc.readingTimeMinutes
      ? `${doc.readingTimeMinutes}`
      : undefined,
    lang: doc.lang as "ar" | "en",
  };
}

/**
 * Get all blog posts for a specific language
 * @param lang - Language code ('ar' or 'en')
 * @param published - Filter by published status (default: true)
 * @returns Array of blog post metadata sorted by date (newest first)
 */
export async function getAllPosts(
  lang: "ar" | "en",
  published: boolean = true,
): Promise<BlogMetadata[]> {
  try {
    const posts = await convexQuery<ConvexBlogPost[]>(
      "content/queries:getAllPosts",
      { lang, published },
    );

    if (!posts) {
      return [];
    }

    return posts.map(mapConvexPostToMetadata);
  } catch (error) {
    console.error("Unexpected error in getAllPosts:", error);
    return [];
  }
}

/**
 * Get a single blog post by slug and language
 * @param slug - Post slug identifier
 * @param lang - Language code ('ar' or 'en')
 * @returns Full blog post with content, or null if not found
 */
export async function getPostBySlug(
  slug: string,
  lang: "ar" | "en",
): Promise<BlogPost | null> {
  try {
    const post = await convexQuery<ConvexBlogPost | null>(
      "content/queries:getPostBySlug",
      { slug, lang },
    );

    if (!post) {
      return null;
    }

    return mapConvexPostToInterface(post);
  } catch (error) {
    console.error("Unexpected error in getPostBySlug:", error);
    return null;
  }
}

/**
 * Get paginated blog posts
 * @param lang - Language code ('ar' or 'en')
 * @param page - Page number (1-indexed, default: 1)
 * @param postsPerPage - Number of posts per page (default: 9)
 * @returns Paginated posts with total pages and count
 */
export async function getPaginatedPosts(
  lang: "ar" | "en",
  page: number = 1,
  postsPerPage: number = 9,
): Promise<{
  posts: BlogMetadata[];
  totalPages: number;
  totalPosts: number;
  currentPage: number;
}> {
  try {
    const result = await convexQuery<{
      posts: ConvexBlogPost[];
      totalPages: number;
      totalPosts: number;
      currentPage: number;
    }>("content/queries:getPaginatedPosts", { lang, page, postsPerPage });

    if (!result) {
      return { posts: [], totalPages: 0, totalPosts: 0, currentPage: page };
    }

    return {
      posts: result.posts.map(mapConvexPostToMetadata),
      totalPages: result.totalPages,
      totalPosts: result.totalPosts,
      currentPage: result.currentPage,
    };
  } catch (error) {
    console.error("Unexpected error in getPaginatedPosts:", error);
    return { posts: [], totalPages: 0, totalPosts: 0, currentPage: page };
  }
}

/**
 * Get all unique tags from published posts
 * @param lang - Language code ('ar' or 'en')
 * @returns Array of unique tag strings sorted alphabetically
 */
export async function getAllTags(lang: "ar" | "en"): Promise<string[]> {
  try {
    const tags = await convexQuery<string[]>("content/queries:getAllTags", {
      lang,
    });

    return tags || [];
  } catch (error) {
    console.error("Unexpected error in getAllTags:", error);
    return [];
  }
}

/**
 * Get all posts that contain a specific tag
 * @param tag - Tag to filter by
 * @param lang - Language code ('ar' or 'en')
 * @returns Array of blog post metadata matching the tag
 */
export async function getPostsByTag(
  tag: string,
  lang: "ar" | "en",
): Promise<BlogMetadata[]> {
  try {
    const posts = await convexQuery<ConvexBlogPost[]>(
      "content/queries:getPostsByTag",
      { tag, lang },
    );

    if (!posts) {
      return [];
    }

    return posts.map(mapConvexPostToMetadata);
  } catch (error) {
    console.error("Unexpected error in getPostsByTag:", error);
    return [];
  }
}

/**
 * Get related posts based on shared tags
 * @param currentSlug - Slug of the current post to exclude
 * @param lang - Language code ('ar' or 'en')
 * @param limit - Maximum number of related posts (default: 3)
 * @returns Array of related blog post metadata sorted by relevance
 */
export async function getRelatedPosts(
  currentSlug: string,
  lang: "ar" | "en",
  limit: number = 3,
): Promise<BlogMetadata[]> {
  try {
    const posts = await convexQuery<ConvexBlogPost[]>(
      "content/queries:getRelatedPosts",
      { currentSlug, lang, limit },
    );

    if (!posts) {
      return [];
    }

    return posts.map(mapConvexPostToMetadata);
  } catch (error) {
    console.error("Unexpected error in getRelatedPosts:", error);
    return [];
  }
}

/**
 * Get all post slugs for static generation
 * @param lang - Language code ('ar' or 'en')
 * @returns Array of post slugs
 */
export async function getAllPostSlugs(lang: "ar" | "en"): Promise<string[]> {
  try {
    const slugs = await convexQuery<string[]>(
      "content/queries:getAllPostSlugs",
      { lang },
    );

    return slugs || [];
  } catch (error) {
    console.error("Unexpected error in getAllPostSlugs:", error);
    return [];
  }
}

// Cached versions — performance optimized with Next.js cache

/**
 * Cached version of getPaginatedPosts
 * Revalidates every hour (3600 seconds)
 */
export const getCachedPaginatedPosts = unstable_cache(
  async (lang: "ar" | "en", page: number = 1, postsPerPage: number = 9) => {
    return getPaginatedPosts(lang, page, postsPerPage);
  },
  ["blog-paginated-posts"],
  { revalidate: 3600, tags: ["blog", "blog-posts"] },
);

/**
 * Cached version of getPostBySlug
 * Revalidates every hour (3600 seconds)
 */
export const getCachedPostBySlug = unstable_cache(
  async (slug: string, lang: "ar" | "en") => {
    return getPostBySlug(slug, lang);
  },
  ["blog-post-by-slug"],
  { revalidate: 3600, tags: ["blog", "blog-posts"] },
);

/**
 * Cached version of getAllPosts
 * Revalidates every hour (3600 seconds)
 */
export const getCachedAllPosts = unstable_cache(
  async (lang: "ar" | "en", published: boolean = true) => {
    return getAllPosts(lang, published);
  },
  ["blog-all-posts"],
  { revalidate: 3600, tags: ["blog", "blog-posts"] },
);

/**
 * Cached version of getAllTags
 * Revalidates every hour (3600 seconds)
 */
export const getCachedAllTags = unstable_cache(
  async (lang: "ar" | "en") => {
    return getAllTags(lang);
  },
  ["blog-tags"],
  { revalidate: 3600, tags: ["blog", "blog-tags"] },
);

/**
 * Cached version of getPostsByTag
 * Revalidates every hour (3600 seconds)
 */
export const getCachedPostsByTag = unstable_cache(
  async (tag: string, lang: "ar" | "en") => {
    return getPostsByTag(tag, lang);
  },
  ["blog-posts-by-tag"],
  { revalidate: 3600, tags: ["blog", "blog-posts", "blog-tags"] },
);

/**
 * Cached version of getRelatedPosts
 * Revalidates every hour (3600 seconds)
 */
export const getCachedRelatedPosts = unstable_cache(
  async (currentSlug: string, lang: "ar" | "en", limit: number = 3) => {
    return getRelatedPosts(currentSlug, lang, limit);
  },
  ["blog-related-posts"],
  { revalidate: 3600, tags: ["blog", "blog-posts"] },
);

/**
 * Cached version of getAllPostSlugs
 * Revalidates every hour (3600 seconds)
 */
export const getCachedAllPostSlugs = unstable_cache(
  async (lang: "ar" | "en") => {
    return getAllPostSlugs(lang);
  },
  ["blog-post-slugs"],
  { revalidate: 3600, tags: ["blog", "blog-posts"] },
);
