import {
  createArticleVersionWithRetry,
  getKbSettings,
  kbTenantQuery,
  type Db,
} from '@zync/db/queries'
import type { KbArticle, SessionPayload } from '@zync/types'

const OWNER_ADMIN_ROLES = new Set(['OWNER', 'ADMIN'])

export type KbPublishTransitionFailure = {
  ok: false
  status: 403 | 404 | 409
  body: { error: string; code?: string }
}

export type KbPublishTransitionSuccess = {
  ok: true
  article: KbArticle
}

export type KbPublishTransitionResult = KbPublishTransitionFailure | KbPublishTransitionSuccess

type PublishTransitionContext = {
  db: Db
  tenantId: string
  articleId: string
  session: SessionPayload
}

/** Review gate + article existence — shared pre-flight for publish transitions. */
export async function validatePublishTransition(
  ctx: Pick<PublishTransitionContext, 'db' | 'tenantId' | 'articleId' | 'session'>,
): Promise<
  | { ok: true; article: KbArticle; kbSettings: Awaited<ReturnType<typeof getKbSettings>> }
  | KbPublishTransitionFailure
> {
  const q = kbTenantQuery(ctx.db, ctx.tenantId)

  const article = await q.getArticleById(ctx.articleId)
  if (!article) {
    return { ok: false, status: 404, body: { error: 'Not found' } }
  }

  const kbSettings = await getKbSettings(ctx.db, ctx.tenantId)

  if (!OWNER_ADMIN_ROLES.has(ctx.session.role ?? '')) {
    if (kbSettings.kb_require_review) {
      return {
        ok: false,
        status: 409,
        body: {
          error: 'Review required. Submit this article for review first.',
          code: 'REVIEW_REQUIRED',
        },
      }
    }
  }

  return { ok: true, article, kbSettings }
}

/** Pre-publish version snapshot (when enabled) + status transition to PUBLISHED. */
export async function performPublishTransition(
  ctx: PublishTransitionContext,
): Promise<KbPublishTransitionResult> {
  const validated = await validatePublishTransition(ctx)
  if (!validated.ok) return validated

  const { article: prePublish, kbSettings } = validated
  const q = kbTenantQuery(ctx.db, ctx.tenantId)

  if (kbSettings.kb_versioning_enabled) {
    await createArticleVersionWithRetry(ctx.db, {
      articleId: prePublish.id,
      tenantId: ctx.tenantId,
      title: prePublish.title,
      content: prePublish.content,
      label: null,
      createdBy: ctx.session.sub,
    })
  }

  try {
    const article = await q.publishArticle(ctx.articleId, ctx.session.sub)
    return { ok: true, article }
  } catch (err) {
    if (err instanceof Error && err.message === 'Article not found') {
      return { ok: false, status: 404, body: { error: 'Not found' } }
    }
    throw err
  }
}

/** Status transition to DRAFT (unpublish). */
export async function performUnpublishTransition(ctx: {
  db: Db
  tenantId: string
  articleId: string
  userId: string
}): Promise<KbPublishTransitionResult> {
  const q = kbTenantQuery(ctx.db, ctx.tenantId)

  try {
    const article = await q.unpublishArticle(ctx.articleId, ctx.userId)
    return { ok: true, article }
  } catch (err) {
    if (err instanceof Error && err.message === 'Article not found') {
      return { ok: false, status: 404, body: { error: 'Not found' } }
    }
    throw err
  }
}
