import { commitImage } from "@/lib/media-manager/commit"
import { MEDIA_FILE_BASE } from "@/lib/media-manager/file-names"
import { revokeStagedImage } from "@/lib/media-manager/stage"
import type { ProcedureMediaSection, StagedImage } from "@/lib/media-manager/types"
import type { Language } from "@/components/dashboard/shared/LanguageTabs"
import type { ProcedureBasicInfoData } from "@/components/dashboard/procedures/ProcedureBasicInfo"
import type { ProcedureOverviewData } from "@/components/dashboard/procedures/ProcedureOverview"
import type { ProcedureBeforeAfterSectionData } from "@/components/dashboard/procedures/ProcedureBeforeAfterSection"
import type { ProcedureReviewItem } from "@/components/dashboard/procedures/ProcedureReviews"

export type ProcedurePendingLocaleKey = `${Language}:${number}`

export function procedurePendingKey(locale: Language, index: number): ProcedurePendingLocaleKey {
  return `${locale}:${index}`
}

export function parseProcedurePendingKey(key: string): { locale: Language; index: number } | null {
  const colon = key.indexOf(":")
  if (colon <= 0) return null
  const locale = key.slice(0, colon) as Language
  if (locale !== "en" && locale !== "ar" && locale !== "tr") return null
  const index = Number(key.slice(colon + 1))
  if (!Number.isInteger(index) || index < 0) return null
  return { locale, index }
}

export interface ProcedurePendingImages {
  mainPhoto: StagedImage | null
  basicBefore: Map<number, StagedImage>
  basicAfter: Map<number, StagedImage>
  overviewCard: Map<ProcedurePendingLocaleKey, StagedImage>
  sectionBefore: Map<ProcedurePendingLocaleKey, StagedImage>
  sectionAfter: Map<ProcedurePendingLocaleKey, StagedImage>
  reviewAvatars: Map<ProcedurePendingLocaleKey, StagedImage>
}

export function createEmptyProcedurePendingImages(): ProcedurePendingImages {
  return {
    mainPhoto: null,
    basicBefore: new Map(),
    basicAfter: new Map(),
    overviewCard: new Map(),
    sectionBefore: new Map(),
    sectionAfter: new Map(),
    reviewAvatars: new Map(),
  }
}

export function procedurePendingHasAny(pending: ProcedurePendingImages): boolean {
  return (
    !!pending.mainPhoto ||
    pending.basicBefore.size > 0 ||
    pending.basicAfter.size > 0 ||
    pending.overviewCard.size > 0 ||
    pending.sectionBefore.size > 0 ||
    pending.sectionAfter.size > 0 ||
    pending.reviewAvatars.size > 0
  )
}

export interface ProcedureLocaleImageSlice {
  overview: ProcedureOverviewData
  beforeAfterSection: ProcedureBeforeAfterSectionData
  reviews: ProcedureReviewItem[]
}

export interface ProcedureFormImageSlice {
  basicInfo: ProcedureBasicInfoData
  translations: Record<Language, ProcedureLocaleImageSlice>
}

export interface CommitPendingProcedureImagesOptions {
  procedureSlug: string
  procedureId?: string
  pending: ProcedurePendingImages
}

/** Upload all pending procedure images, merge URLs into form slice, clear pending. */
export async function commitPendingProcedureImages(
  slice: ProcedureFormImageSlice,
  options: CommitPendingProcedureImagesOptions
): Promise<ProcedureFormImageSlice> {
  const procedureSlug = options.procedureSlug.trim()
  if (!procedureSlug) {
    throw new Error("Procedure slug is required before saving images.")
  }

  let basicInfo = {
    ...slice.basicInfo,
    beforeAfterImages: slice.basicInfo.beforeAfterImages.map((item) => ({ ...item })),
  }
  const translations = {
    en: {
      overview: { ...slice.translations.en.overview },
      beforeAfterSection: {
        ...slice.translations.en.beforeAfterSection,
        results: slice.translations.en.beforeAfterSection.results.map((item) => ({ ...item })),
      },
      reviews: slice.translations.en.reviews.map((item) => ({ ...item })),
    },
    ar: {
      overview: { ...slice.translations.ar.overview },
      beforeAfterSection: {
        ...slice.translations.ar.beforeAfterSection,
        results: slice.translations.ar.beforeAfterSection.results.map((item) => ({ ...item })),
      },
      reviews: slice.translations.ar.reviews.map((item) => ({ ...item })),
    },
    tr: {
      overview: { ...slice.translations.tr.overview },
      beforeAfterSection: {
        ...slice.translations.tr.beforeAfterSection,
        results: slice.translations.tr.beforeAfterSection.results.map((item) => ({ ...item })),
      },
      reviews: slice.translations.tr.reviews.map((item) => ({ ...item })),
    },
  }

  if (options.pending.mainPhoto) {
    const committed = await commitImage({
      entity: "procedure",
      staged: options.pending.mainPhoto,
      procedureSlug,
      section: "main-photo",
      fileBaseName: MEDIA_FILE_BASE.mainPhoto,
      procedureId: options.procedureId,
    })
    revokeStagedImage(options.pending.mainPhoto)
    basicInfo = {
      ...basicInfo,
      mainImage: committed.url,
      mainImagePublicId: committed.publicId,
    }
    options.pending.mainPhoto = null
  }

  const basicBeforeIndices = [...options.pending.basicBefore.keys()].sort((a, b) => a - b)
  for (const index of basicBeforeIndices) {
    const staged = options.pending.basicBefore.get(index)
    if (!staged) continue
    const committed = await commitImage({
      entity: "procedure",
      staged,
      procedureSlug,
      section: "before-after-hero",
      fileBaseName: MEDIA_FILE_BASE.beforeAfter,
      filePart: "before",
      fileIndex: index,
      procedureId: options.procedureId,
    })
    revokeStagedImage(staged)
    options.pending.basicBefore.delete(index)
    if (basicInfo.beforeAfterImages[index]) {
      basicInfo.beforeAfterImages[index] = {
        ...basicInfo.beforeAfterImages[index],
        beforeImage: committed.url,
        beforeImagePublicId: committed.publicId,
      }
    }
  }

  const basicAfterIndices = [...options.pending.basicAfter.keys()].sort((a, b) => a - b)
  for (const index of basicAfterIndices) {
    const staged = options.pending.basicAfter.get(index)
    if (!staged) continue
    const committed = await commitImage({
      entity: "procedure",
      staged,
      procedureSlug,
      section: "before-after-hero",
      fileBaseName: MEDIA_FILE_BASE.beforeAfter,
      filePart: "after",
      fileIndex: index,
      procedureId: options.procedureId,
    })
    revokeStagedImage(staged)
    options.pending.basicAfter.delete(index)
    if (basicInfo.beforeAfterImages[index]) {
      basicInfo.beforeAfterImages[index] = {
        ...basicInfo.beforeAfterImages[index],
        afterImage: committed.url,
        afterImagePublicId: committed.publicId,
      }
    }
  }

  async function commitLocaleMap(
    map: Map<ProcedurePendingLocaleKey, StagedImage>,
    section: ProcedureMediaSection,
    fileBaseName: string,
    mapOptions: { part?: "before" | "after" },
    apply: (locale: Language, index: number, url: string, publicId: string) => void
  ) {
    const keys = [...map.keys()].sort()
    for (const key of keys) {
      const staged = map.get(key)
      if (!staged) continue
      const parsed = parseProcedurePendingKey(key)
      if (!parsed) continue
      const committed = await commitImage({
        entity: "procedure",
        staged,
        procedureSlug,
        section,
        fileBaseName,
        fileIndex: parsed.index,
        filePart: mapOptions.part,
        procedureId: options.procedureId,
      })
      revokeStagedImage(staged)
      map.delete(key)
      apply(parsed.locale, parsed.index, committed.url, committed.publicId)
    }
  }

  await commitLocaleMap(
    options.pending.overviewCard,
    "overview",
    MEDIA_FILE_BASE.overview,
    {},
    (locale, _index, url, publicId) => {
    translations[locale].overview = {
      ...translations[locale].overview,
      overviewCardImage: url,
      overviewCardImagePublicId: publicId,
    }
  })

  await commitLocaleMap(
    options.pending.sectionBefore,
    "before-after-gallery",
    MEDIA_FILE_BASE.beforeAfter,
    { part: "before" },
    (locale, index, url, publicId) => {
    const items = translations[locale].beforeAfterSection.results
    if (items[index]) {
      items[index] = { ...items[index], beforeImage: url, beforeImagePublicId: publicId }
    }
  })

  await commitLocaleMap(
    options.pending.sectionAfter,
    "before-after-gallery",
    MEDIA_FILE_BASE.beforeAfter,
    { part: "after" },
    (locale, index, url, publicId) => {
    const items = translations[locale].beforeAfterSection.results
    if (items[index]) {
      items[index] = { ...items[index], afterImage: url, afterImagePublicId: publicId }
    }
  })

  await commitLocaleMap(
    options.pending.reviewAvatars,
    "reviews",
    MEDIA_FILE_BASE.reviews,
    {},
    (locale, index, url, publicId) => {
    const items = translations[locale].reviews
    if (items[index]) {
      items[index] = { ...items[index], avatar: url, avatarPublicId: publicId }
    }
  })

  return { basicInfo, translations }
}

export function clearProcedurePendingImages(pending: ProcedurePendingImages) {
  if (pending.mainPhoto) revokeStagedImage(pending.mainPhoto)
  pending.mainPhoto = null
  for (const map of [
    pending.basicBefore,
    pending.basicAfter,
    pending.overviewCard,
    pending.sectionBefore,
    pending.sectionAfter,
    pending.reviewAvatars,
  ]) {
    for (const staged of map.values()) {
      revokeStagedImage(staged)
    }
    map.clear()
  }
}
