import {ExecArgs} from "@medusajs/framework/types"
import {existsSync, readFileSync} from "node:fs"
import path from "node:path"
import {fetchSanityProductForSync, syncSanityProductToMedusa} from "../lib/sanity-product-sync"

function loadEnvFile(filePath: string) {
  if (!existsSync(filePath)) return

  const content = readFileSync(filePath, "utf8")
  for (const line of content.split(/\r?\n/)) {
    const match = line.match(/^\s*([^#=\s]+)\s*=\s*(.*)\s*$/)
    if (!match) continue

    const key = match[1]
    const value = match[2].trim().replace(/^['"]|['"]$/g, "")
    if (!(key in process.env)) {
      process.env[key] = value
    }
  }
}

function findRepoRoot() {
  const candidates = [process.cwd(), path.resolve(process.cwd(), "../..")]
  return candidates.find((candidate) => existsSync(path.join(candidate, "apps/cms/.env"))) || process.cwd()
}

function loadSanityEnvFiles() {
  const repoRoot = findRepoRoot()
  loadEnvFile(path.join(repoRoot, "apps/cms/.env"))
  loadEnvFile(path.join(repoRoot, "apps/cms/.env.local"))
  loadEnvFile(path.join(repoRoot, "apps/storefront/.env.local"))
}

async function findSanityProductIdByHandle(handle: string) {
  const projectId =
    process.env.SANITY_PROJECT_ID ||
    process.env.SANITY_STUDIO_PROJECT_ID ||
    process.env.NEXT_PUBLIC_SANITY_PROJECT_ID ||
    ""
  const dataset =
    process.env.SANITY_DATASET ||
    process.env.SANITY_STUDIO_DATASET ||
    process.env.NEXT_PUBLIC_SANITY_DATASET ||
    "production"
  const apiVersion = process.env.SANITY_API_VERSION || process.env.NEXT_PUBLIC_SANITY_API_VERSION || "2025-01-01"
  const token = process.env.SANITY_API_READ_TOKEN || process.env.SANITY_API_WRITE_TOKEN || ""

  if (!projectId) {
    throw new Error("Missing SANITY_PROJECT_ID for product sync script.")
  }

  const url = new URL(`https://${projectId}.api.sanity.io/v${apiVersion}/data/query/${dataset}`)
  url.searchParams.set("query", `*[_type == "product" && slug.current == $handle][0]{ _id }`)
  url.searchParams.set("$handle", JSON.stringify(handle))

  const headers: Record<string, string> = {
    accept: "application/json",
  }

  if (token) {
    headers.authorization = `Bearer ${token}`
  }

  const response = await fetch(url, {
    method: "GET",
    headers,
    cache: "no-store",
  })

  if (!response.ok) {
    throw new Error(`Sanity fetch failed (${response.status}).`)
  }

  const json = (await response.json()) as {result?: {_id?: string | null} | null}
  return String(json.result?._id || "").trim()
}

export default async function syncSanityProductScript({container}: ExecArgs) {
  loadSanityEnvFiles()

  const handles = (process.env.SANITY_PRODUCT_HANDLES || process.env.SANITY_PRODUCT_HANDLE || "tonies-1")
    .split(/[\s,]+/)
    .map((handle) => handle.trim())
    .filter(Boolean)
  const allowSanityWriteback = process.env.SANITY_SYNC_WRITEBACK === "1"

  if (!handles.length) {
    throw new Error("Missing SANITY_PRODUCT_HANDLE or SANITY_PRODUCT_HANDLES.")
  }

  const results: Array<Record<string, unknown>> = []

  for (const handle of handles) {
    const documentId = await findSanityProductIdByHandle(handle)

    if (!documentId) {
      throw new Error(`Product ${handle} not found in Sanity.`)
    }

    const product = await fetchSanityProductForSync(documentId)

    if (!product) {
      throw new Error(`Unable to fetch published Sanity payload for ${handle}.`)
    }

    const result = await syncSanityProductToMedusa(container as any, {
      ...product,
      _id: documentId,
    }, {
      allowSanityWriteback,
    })

    results.push({documentId, allowSanityWriteback, ...result})
  }

  console.log(JSON.stringify(results.length === 1 ? results[0] : results, null, 2))
}
