import fs from 'fs'
import path from 'path'
import crypto from 'crypto'

const APP_PACKAGE_ROOT = path.resolve(__dirname, '..', '..', '..')
const APP_SOURCE_ROOT = path.join(APP_PACKAGE_ROOT, 'src')
const APP_DIST_ROOT = path.join(APP_PACKAGE_ROOT, 'dist')
const DEFAULT_STORAGE_ROOT = path.join(APP_PACKAGE_ROOT, 'storage')
const LEGACY_STORAGE_ROOTS = [
  path.join(APP_SOURCE_ROOT, 'lib', 'storage'),
]

export type StorageVisibility = 'public' | 'private'

export function getStorageRoot(): string {
  return process.env.FILE_STORAGE_ROOT
    ? path.resolve(process.env.FILE_STORAGE_ROOT)
    : DEFAULT_STORAGE_ROOT
}

export function getPublicStorageRoot(): string {
  return path.join(getStorageRoot(), 'public')
}

export function getPrivateStorageRoot(): string {
  return path.join(getStorageRoot(), 'private')
}

export function getLegacyStorageRoots(): string[] {
  return LEGACY_STORAGE_ROOTS
}

function isWithinPath(targetPath: string, parentPath: string): boolean {
  const relative = path.relative(parentPath, targetPath)
  return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))
}

export function assertStorageConfiguration(): string {
  const storageRoot = getStorageRoot()

  if (process.env.NODE_ENV === 'production' && !process.env.FILE_STORAGE_ROOT) {
    throw new Error('FILE_STORAGE_ROOT must be set in production so uploads are stored on the mounted volume.')
  }

  if (process.env.NODE_ENV === 'production') {
    const forbiddenRoots = [APP_PACKAGE_ROOT, APP_SOURCE_ROOT, APP_DIST_ROOT]
    const invalidRoot = forbiddenRoots.find((root) => isWithinPath(storageRoot, root))
    if (invalidRoot) {
      throw new Error(
        `FILE_STORAGE_ROOT must point outside the API app tree in production. Received ${storageRoot}, which is inside ${invalidRoot}.`
      )
    }
  }

  return storageRoot
}

function ensureStorageRoot(visibility: StorageVisibility): string {
  assertStorageConfiguration()
  const root = visibility === 'public' ? getPublicStorageRoot() : getPrivateStorageRoot()
  fs.mkdirSync(root, { recursive: true })
  return root
}

function inferVisibility(folder: string): StorageVisibility {
  const normalized = folder.replace(/\\/g, '/')
  if (/\/customers\//.test(`/${normalized}/`)) return 'private'
  if (/\/licenses?\//.test(`/${normalized}/`)) return 'private'
  if (/\/contracts?\//.test(`/${normalized}/`)) return 'private'
  if (/\/documents?\//.test(`/${normalized}/`)) return 'private'
  if (/\/inspections?\//.test(`/${normalized}/`)) return 'private'
  if (/\/internal\//.test(`/${normalized}/`)) return 'private'
  return 'public'
}

function getApiBase(): string {
  return (process.env.API_URL ?? 'http://localhost:4000').replace(/\/$/, '')
}

function getDashboardBase(): string {
  return (
    process.env.DASHBOARD_URL ??
    process.env.NEXT_PUBLIC_DASHBOARD_URL ??
    'http://localhost:3000/dashboard'
  ).replace(/\/$/, '')
}

function getStorageRelativePath(imageUrl: string): string | null {
  const marker = '/storage/'
  const idx = imageUrl.indexOf(marker)
  if (idx === -1) return null
  return imageUrl.slice(idx + marker.length)
}

export function getProtectedCustomerLicenseImageUrl(customerId: string): string {
  return `${getDashboardBase()}/api/v1/customers/${customerId}/license-image`
}

export async function uploadImage(
  buffer: Buffer,
  folder: string,
  publicId?: string,
  visibility: StorageVisibility = inferVisibility(folder),
): Promise<string> {
  const storageRoot = ensureStorageRoot(visibility)
  const folderPath = path.join(storageRoot, folder)
  if (!isWithinPath(folderPath, storageRoot)) {
    throw new Error('Upload path escapes storage root')
  }
  fs.mkdirSync(folderPath, { recursive: true })

  const filename = publicId
    ? `${publicId}.jpg`
    : `${crypto.randomBytes(16).toString('hex')}.jpg`

  fs.writeFileSync(path.join(folderPath, filename), buffer)

  return `${getApiBase()}/storage/${folder}/${filename}`
}

export function resolveStoredFilePath(imageUrl: string): string | null {
  const relative = getStorageRelativePath(imageUrl)
  if (!relative) return null

  const roots = [getPublicStorageRoot(), getPrivateStorageRoot(), ...getLegacyStorageRoots(), assertStorageConfiguration()]
  for (const root of roots) {
    const filePath = path.join(root, relative)
    if (!isWithinPath(filePath, root)) continue
    if (fs.existsSync(filePath)) {
      return filePath
    }
  }

  return null
}

export async function deleteImage(imageUrl: string): Promise<void> {
  const filePath = resolveStoredFilePath(imageUrl)
  if (filePath && fs.existsSync(filePath)) {
    fs.unlinkSync(filePath)
  }
}
