/**
 * Posts service — thin client over the CMS REST endpoints, shaped around the
 * data the Posts admin area needs.
 *
 * `fetchPosts` calls the server-side aggregate endpoint `GET /posts`, which
 * does the cross-collection filter / sort / paginate at the DB level (one
 * query + one count) and returns the post rows alongside dataset-wide type
 * counts and the contributor list. This keeps the Posts list O(page) instead
 * of pulling every document per type into the browser, and lets it scale past
 * the old ~500-row-per-type client cap.
 *
 * Access control still lives server-side: the endpoint only returns rows from
 * collections the caller's scope can read.
 */
import { cmsApi } from './api.js'

export type PostStatus = 'DRAFT' | 'PUBLISHED' | 'SCHEDULED' | 'ARCHIVED'

export interface PostType {
  id: string // == slug
  slug: string
  name: string // plural label
  singularName: string
  description: string | null
  urlBase: string
  accentColor: string | null
  icon: string | null
  postCount: number
  fieldCount: number
  active: boolean
}

export interface PostAuthor {
  id: string
  name: string
  initials: string
}

export interface Post {
  id: string
  title: string
  slug: string
  postTypeId: string
  postTypeName: string
  postTypeAccentColor: string | null
  authorId: string
  authorName: string
  authorInitials: string
  status: PostStatus
  publishDate: string | null
  updatedDate: string
  seoScore: number | null
  createdAt: string
  updatedAt: string
}

export interface PostsQuery {
  search?: string
  postType?: string | 'all'
  status?: PostStatus | 'all'
  author?: string | 'all'
  sortBy?: 'title' | 'type' | 'author' | 'status' | 'date' | 'seo'
  sortDirection?: 'asc' | 'desc'
  page?: number
  pageSize?: number
}

export interface PostsResult {
  posts: Post[]
  total: number
  page: number
  pageSize: number
  types: PostType[]
  authors: PostAuthor[]
}

// ─── Collections → Post Types ────────────────────────────────────────

interface CollectionApiRow {
  slug: string
  labels: { singular: string; plural: string }
  type: string
  urlPrefix: string
  description: string | null
  icon: string | null
  color: string | null
  group: string | null
  hidden: boolean
  fieldCount: number
}

function isPostsCollection(c: CollectionApiRow): boolean {
  return c.type === 'post' || (typeof c.group === 'string' && c.group.toLowerCase() === 'posts')
}

async function fetchPostCollections(): Promise<CollectionApiRow[]> {
  const res = await cmsApi<CollectionApiRow[]>('/collections')
  if (res.error || !res.data) return []
  return res.data.filter((c) => !c.hidden && isPostsCollection(c))
}

export async function fetchPostTypes(): Promise<PostType[]> {
  const cols = await fetchPostCollections()
  // Counts are filled in by `fetchPosts` so the cards / tabs reflect
  // the same numbers users see in the table. When called from a page
  // that doesn't load posts (the New Post picker), the count stays
  // at 0 until the next fetchPosts call.
  return cols.map(collectionToPostType)
}

function collectionToPostType(c: CollectionApiRow, count = 0): PostType {
  return {
    id: c.slug,
    slug: c.slug,
    name: c.labels.plural,
    singularName: c.labels.singular,
    description: c.description ?? null,
    urlBase: `/${c.urlPrefix || c.slug}`,
    accentColor: c.color ?? null,
    icon: c.icon ?? null,
    postCount: count,
    fieldCount: c.fieldCount,
    active: true,
  }
}

// ─── Authors ─────────────────────────────────────────────────────────

function initialsFromName(name: string | null | undefined): string {
  const trimmed = name?.trim()
  if (!trimmed) return '?'
  const parts = trimmed.split(/\s+/)
  const first = parts[0]?.[0] ?? ''
  const last = parts.length > 1 ? (parts[parts.length - 1]?.[0] ?? '') : ''
  return (first + last).toUpperCase() || '?'
}

// ─── Posts (server-side aggregate) ───────────────────────────────────

interface PostsApiPost {
  id: string
  collection: string
  title: string | null
  slug: string | null
  status: PostStatus
  publishedAt: string | null
  scheduledAt: string | null
  createdAt: string
  updatedAt: string
  seoScore: number | null
  author: { id: string; name: string } | null
}

interface PostsApiType {
  slug: string
  singular: string
  plural: string
  description: string | null
  urlPrefix: string
  color: string | null
  icon: string | null
  fieldCount: number
  count: number
}

interface PostsApiResponse {
  posts: PostsApiPost[]
  total: number
  page: number
  pageSize: number
  types: PostsApiType[]
  authors: Array<{ id: string; name: string }>
}

/** Display date matches the old client behaviour: scheduled/published date when set, else updated. */
function pickDisplayDate(d: PostsApiPost): string {
  if (d.status === 'SCHEDULED' && d.scheduledAt) return d.scheduledAt
  if (d.status === 'PUBLISHED' && d.publishedAt) return d.publishedAt
  return d.updatedAt
}

function buildPostsQueryString(query: PostsQuery): string {
  const params = new URLSearchParams()
  if (query.search?.trim()) params.set('search', query.search.trim())
  if (query.postType && query.postType !== 'all') params.set('postType', query.postType)
  if (query.status && query.status !== 'all') params.set('status', query.status)
  if (query.author && query.author !== 'all') params.set('author', query.author)
  if (query.sortBy) params.set('sortBy', query.sortBy)
  if (query.sortDirection) params.set('sortDirection', query.sortDirection)
  params.set('page', String(Math.max(1, query.page ?? 1)))
  params.set('pageSize', String(Math.max(1, query.pageSize ?? 10)))
  const qs = params.toString()
  return qs ? `?${qs}` : ''
}

export async function fetchPosts(query: PostsQuery = {}): Promise<PostsResult> {
  const page = Math.max(1, query.page ?? 1)
  const pageSize = Math.max(1, query.pageSize ?? 10)

  const res = await cmsApi<PostsApiResponse>(`/posts${buildPostsQueryString(query)}`)
  if (res.error || !res.data) {
    throw new Error(res.error ?? 'Failed to load posts')
  }
  const r = res.data

  const typeBySlug = new Map<string, PostsApiType>()
  for (const t of r.types) typeBySlug.set(t.slug, t)

  const types: PostType[] = r.types.map((t) => ({
    id: t.slug,
    slug: t.slug,
    name: t.plural,
    singularName: t.singular,
    description: t.description ?? null,
    urlBase: `/${t.urlPrefix || t.slug}`,
    accentColor: t.color ?? null,
    icon: t.icon ?? null,
    postCount: t.count,
    fieldCount: t.fieldCount,
    active: true,
  }))

  const posts: Post[] = r.posts.map((d) => {
    const type = typeBySlug.get(d.collection)
    const authorName = d.author?.name?.trim() || 'Unknown'
    return {
      id: d.id,
      title: d.title ?? '(untitled)',
      slug: d.slug ?? '',
      postTypeId: d.collection,
      postTypeName: type?.singular ?? d.collection,
      postTypeAccentColor: type?.color ?? null,
      authorId: d.author?.id ?? '',
      authorName,
      authorInitials: d.author ? initialsFromName(d.author.name) : '??',
      status: d.status,
      publishDate: d.publishedAt ?? d.scheduledAt ?? null,
      updatedDate: pickDisplayDate(d),
      seoScore: d.seoScore,
      createdAt: d.createdAt,
      updatedAt: d.updatedAt,
    }
  })

  const authors: PostAuthor[] = r.authors
    .map((a) => ({
      id: a.id,
      name: a.name?.trim() || 'Unknown',
      initials: initialsFromName(a.name),
    }))
    .sort((a, b) => a.name.localeCompare(b.name))

  return {
    posts,
    total: r.total,
    page: r.page ?? page,
    pageSize: r.pageSize ?? pageSize,
    types,
    authors,
  }
}

// ─── Bulk mutations ──────────────────────────────────────────────────

export async function bulkUpdatePosts(
  ids: Array<{ postTypeId: string; id: string }>,
  payload: { status?: PostStatus },
): Promise<{ ok: number; failed: number }> {
  let ok = 0
  let failed = 0
  for (const { postTypeId, id } of ids) {
    const res = await cmsApi(`/collections/${encodeURIComponent(postTypeId)}/${id}`, {
      method: 'PUT',
      body: JSON.stringify(payload),
    })
    if (res.error) failed++
    else ok++
  }
  return { ok, failed }
}

export async function bulkDeletePosts(
  ids: Array<{ postTypeId: string; id: string }>,
): Promise<{ ok: number; failed: number }> {
  let ok = 0
  let failed = 0
  for (const { postTypeId, id } of ids) {
    const res = await cmsApi(`/collections/${encodeURIComponent(postTypeId)}/${id}`, {
      method: 'DELETE',
    })
    if (res.error) failed++
    else ok++
  }
  return { ok, failed }
}
