import { File as ExpoFile } from 'expo-file-system'
import type { Visibility } from 'src/lib/api-types'
import { AccountStore } from 'src/state/accountStore'
import { appStorage } from 'src/state/storage'
import { DRAFT_KEY_PREFIX, draftKey } from './draftRegistry'
import type { MediaAsset } from './types'

// Draft load/save layer. The MMKV key shape + registry-teardown helpers
// (clearDraftFor, clearAllDrafts) live in `./draftRegistry` so that
// `src/state/accountStore.ts` can reach the teardown side without
// importing this file (which transitively imports `accountStore` again
// via the AccountStore handle below).

function activeDraftKey(): string {
  return draftKey(AccountStore.activeIdOrThrow())
}

export type DraftMedia = Pick<
  MediaAsset,
  'uri' | 'kind' | 'mimeType' | 'altText' | 'width' | 'height' | 'durationMs'
>

export type ComposerDraft = {
  caption: string
  scope: Visibility
  sensitive: boolean
  /** Compose Redesign Phase 3: optional content-warning text. Persisted so a
   * resumed draft restores the CW alongside the sensitive flag. Empty string
   * when unset. Pre-Phase-3 drafts will lack this key; readers default to ''. */
  spoilerText: string
  media: DraftMedia[]
  quotedStatusId: string | null
  savedAt: number
}

/** Reads the active account's stored draft and drops media that no longer
 *  exists on disk (iOS aggressively purges the picker cache between
 *  sessions). */
export function loadDraft(): ComposerDraft | null {
  const raw = appStorage.getString(activeDraftKey())
  if (!raw) return null
  try {
    const parsed = JSON.parse(raw) as ComposerDraft
    const surviving = parsed.media.filter((m) => {
      try {
        return new ExpoFile(m.uri).exists
      } catch {
        return false
      }
    })
    if (surviving.length !== parsed.media.length) {
      return { ...parsed, media: surviving }
    }
    return parsed
  } catch {
    return null
  }
}

export function saveDraft(draft: Omit<ComposerDraft, 'savedAt'>): void {
  const hasContent =
    draft.caption.trim().length > 0 ||
    draft.media.length > 0 ||
    !!draft.quotedStatusId ||
    draft.spoilerText.trim().length > 0
  if (!hasContent) {
    clearDraft()
    return
  }
  const payload: ComposerDraft = { ...draft, savedAt: Date.now() }
  try {
    appStorage.set(activeDraftKey(), JSON.stringify(payload))
  } catch {
    /* quota or serialization — drop silently, drafts are best-effort */
  }
}

export function clearDraft(): void {
  appStorage.remove(activeDraftKey())
}

/**
 * Sum the on-disk size of every media file referenced by every saved draft
 * across all accounts. Returns 0 when no drafts exist or when every
 * referenced URI has been purged from the picker cache by the OS. Used by
 * the Settings → Storage screen to surface the drafts footprint honestly
 * without conflating it with the cache categories — drafts are user data
 * and never get bulk-cleared.
 *
 * The MMKV JSON itself is negligible (a few hundred bytes per draft); the
 * disk weight is in the picker-cache files the URIs point at.
 */
export function getAllDraftsBytes(): number {
  let total = 0
  for (const k of appStorage.getAllKeys()) {
    if (!k.startsWith(DRAFT_KEY_PREFIX)) continue
    const raw = appStorage.getString(k)
    if (!raw) continue
    try {
      const parsed = JSON.parse(raw) as ComposerDraft
      for (const m of parsed.media) {
        try {
          const f = new ExpoFile(m.uri)
          if (f.exists) total += f.size
        } catch {
          /* missing file — drop silently */
        }
      }
    } catch {
      /* malformed draft — skip */
    }
  }
  return total
}

export function toDraftMedia(media: MediaAsset[]): DraftMedia[] {
  return media.map((m) => ({
    uri: m.uri,
    kind: m.kind,
    mimeType: m.mimeType,
    altText: m.altText,
    width: m.width,
    height: m.height,
    durationMs: m.durationMs,
  }))
}
