const multer = require('multer')
const path = require('path')
const fs = require('fs')
const config = require('../config/config')

const ABSOLUTE_URL_REGEX = /^https?:\/\//i
const SPECIAL_URL_PREFIXES = ['data:', 'blob:']

const resolveUploadBasePath = () => {
  return path.isAbsolute(config.upload.uploadPath)
    ? config.upload.uploadPath
    : path.resolve(__dirname, '..', '..', config.upload.uploadPath)
}

// Resolve public images path for department logos
const resolvePublicImagesPath = (subfolder) => {
  const publicPath = path.resolve(__dirname, '..', '..', 'public', 'Images', subfolder)
  return publicPath
}

const createStorage = (folder) => multer.diskStorage({
  destination: (req, file, cb) => {
    // For department, user, and organization folders, use public/Images/
    let uploadDir
    if (folder === 'department') {
      uploadDir = resolvePublicImagesPath('department')
    } else if (folder === 'user') {
      uploadDir = resolvePublicImagesPath('user')
    } else if (folder === 'contacts') {
      uploadDir = resolvePublicImagesPath('contacts')
    } else if (folder === 'organization') {
      uploadDir = resolvePublicImagesPath('organization')
    } else {
      uploadDir = path.join(resolveUploadBasePath(), folder)
    }

    fs.promises.mkdir(uploadDir, { recursive: true })
      .then(() => cb(null, uploadDir))
      .catch(err => cb(err))
  },
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname) || ''
    const uniqueName = `${Date.now()}-${Math.round(Math.random() * 1e9)}${ext}`
    cb(null, uniqueName)
  }
})

const imageFileFilter = (req, file, cb) => {
  if (!file.mimetype || !file.mimetype.startsWith('image/')) {
    const error = new Error('Invalid file type. Only image uploads are allowed.')
    error.status = 400
    return cb(error)
  }

  cb(null, true)
}

const createImageUploader = (folder) => multer({
  storage: createStorage(folder),
  limits: {
    fileSize: config.upload.maxFileSize
  },
  fileFilter: imageFileFilter
})

const normalizeFieldNames = (fieldNames) => {
  if (!Array.isArray(fieldNames)) {
    return [fieldNames].filter(Boolean)
  }
  return Array.from(new Set(fieldNames.filter(Boolean)))
}

const createOptionalImageUploadMiddleware = (fieldNames, folder) => {
  const uploader = createImageUploader(folder)
  const normalizedFields = normalizeFieldNames(fieldNames)
  if (normalizedFields.length === 0) {
    throw new Error('At least one field name must be provided for image upload middleware')
  }

  return (req, res, next) => {
    const contentType = req.headers['content-type'] || ''

    if (!contentType.toLowerCase().includes('multipart/form-data')) {
      return next()
    }

    // Use .any() to parse ALL fields (both text and file)
    // Multer automatically puts text fields in req.body and files in req.files
    const uploadHandler = uploader.any()

    uploadHandler(req, res, (err) => {
      if (err) {
        if (!err.status) {
          err.status = 400
        }
        err.message = err.message || 'Image upload failed'
        return next(err)
      }

      // Find the file from the specified field names
      // req.files is an array when using .any()
      if (req.files && Array.isArray(req.files)) {
        for (const file of req.files) {
          if (normalizedFields.includes(file.fieldname)) {
            req.file = file
            break
          }
        }
        // Fallback: if no exact fieldname match found, but a file exists, take the first file
        if (!req.file && req.files.length > 0) {
          req.file = req.files[0]
        }
      }

      // Log parsed data for debugging
      console.log('📦 Multer parsed - req.body keys:', Object.keys(req.body))
      console.log('📦 Multer parsed - req.body:', req.body)
      console.log('📦 Multer parsed - req.file:', req.file ? req.file.filename : 'No file')
      if (req.files && Array.isArray(req.files)) {
        console.log('📦 Multer parsed - req.files count:', req.files.length)
        req.files.forEach((f, i) => {
          console.log(`📦 Multer parsed - req.files[${i}]:`, f.fieldname, f.filename)
        })
      }

      return next()
    })
  }
}

const buildPublicUploadPath = (folder, filename) => {
  if (!filename) return null
  // For department, user, and organization, use /Images/ path
  if (folder === 'department') {
    return path.posix.join('/Images', 'department', filename)
  }
  if (folder === 'user') {
    return path.posix.join('/Images', 'user', filename)
  }
  if (folder === 'contacts') {
    return path.posix.join('/Images', 'contacts', filename)
  }
  if (folder === 'organization') {
    return path.posix.join('/Images', 'organization', filename)
  }
  return path.posix.join('/uploads', folder, filename)
}

const getRequestBaseUrl = (req) => {
  const forwardedProto = req.headers['x-forwarded-proto']
  const protoRaw = forwardedProto || req.protocol || 'http'
  const protocol = (Array.isArray(protoRaw) ? protoRaw[0] : String(protoRaw)).split(',')[0].trim() || 'http'

  const fHostRaw = req.headers['x-forwarded-host'] || req.get('x-forwarded-host')
  const fPortRaw = req.headers['x-forwarded-port'] || req.get('x-forwarded-port')
  const hostHeader = req.headers['host'] || req.get('host')
  const hostname = req.hostname || undefined

  let host = ''
  if (fHostRaw) {
    host = String(fHostRaw).split(',')[0].trim()
  } else if (hostHeader) {
    host = String(hostHeader).trim()
  } else if (hostname) {
    const port = config.port || 80
    host = port === 80 ? String(hostname) : `${String(hostname)}:${port}`
  } else {
    const port = config.port || 80
    host = port === 80 ? 'localhost' : `localhost:${port}`
  }

  if (fPortRaw && !/:(\d+)$/.test(host)) {
    const p = String(fPortRaw).split(',')[0].trim()
    if (p) host = `${host}:${p}`
  }

  return `${protocol}://${host}`
}

const ensureAbsoluteUrl = (req, targetPath) => {
  if (!targetPath) return null

  const value = String(targetPath).trim()
  if (value === '') return null

  const lowerValue = value.toLowerCase()
  if (ABSOLUTE_URL_REGEX.test(lowerValue) || SPECIAL_URL_PREFIXES.some(prefix => lowerValue.startsWith(prefix))) {
    return value.replace(/\\/g, '/')
  }

  const normalizedPath = value.replace(/\\/g, '/')
  const ensureLeadingSlash = normalizedPath.startsWith('/') ? normalizedPath : `/${normalizedPath}`

  let baseUrl = getRequestBaseUrl(req)
  // Force Images to use port 83 (or configured base URL)
  if (ensureLeadingSlash.startsWith('/Images')) {
    if (config.publicImagesBaseUrl) {
      baseUrl = config.publicImagesBaseUrl
    } else {
      try {
        const u = new URL(baseUrl)
        u.port = '83'
        baseUrl = `${u.protocol}//${u.hostname}${u.port ? `:${u.port}` : ''}`
      } catch {
        // Fallback: strip any existing port and append :83
        baseUrl = baseUrl.replace(/:(\d+)$/, '')
        if (!/:(\d+)$/.test(baseUrl)) {
          baseUrl = `${baseUrl}:83`
        }
      }
    }
  }

  return `${baseUrl}${ensureLeadingSlash}`
}

// Normalize any given path/URL to a relative Images path
const ensureImagesRelativePath = (subfolder, targetPath) => {
  if (!targetPath) return null
  let value = String(targetPath).trim().replace(/\\/g, '/')
  if (!value) return null

  // Strip any absolute URL prefixes
  value = value.replace(/^https?:\/\/[^/]+/i, '')
  // Also remove accidental repeated host fragments
  value = value.replace(/https?:\/\/[^/]+/gi, '')

  // Ensure leading slash for consistent matching
  value = value.startsWith('/') ? value : `/${value}`

  // If already contains /Images, return from that segment
  const imagesIdx = value.toLowerCase().indexOf('/images/')
  if (imagesIdx !== -1) {
    const original = value.substring(imagesIdx)
    const after = original.substring('/Images/'.length)
    const parts = after.split('/')
    const currentFolder = parts[0] || ''
    const sf = (subfolder || '').toString()
    if (sf && currentFolder && currentFolder.toLowerCase() !== sf.toLowerCase()) {
      parts[0] = sf
      return `/Images/${parts.join('/')}`
    }
    return original
  }

  // Map legacy /uploads paths to /Images/<subfolder>
  const uploadsIdx = value.toLowerCase().indexOf('/uploads/')
  if (uploadsIdx !== -1) {
    let tail = value.substring(uploadsIdx + '/uploads/'.length)
    tail = tail.replace(/^\/+/, '')
    const sf = (subfolder || '').toString()
    if (!sf) return `/Images/${tail}`
    const prefix = sf.toLowerCase() + '/'
    if (!tail.toLowerCase().startsWith(prefix)) {
      tail = `${sf}/${tail}`
    }
    return `/Images/${tail}`
  }

  // Fallback: construct Images path using provided subfolder
  const sf = (subfolder || '').toString()
  const name = value.replace(/^\/+/, '')
  if (sf) {
    if (name.toLowerCase().startsWith(sf.toLowerCase() + '/')) {
      return `/Images/${name}`
    }
    return `/Images/${sf}/${name}`
  }
  return name.startsWith('Images/') ? `/${name}` : `/Images/${name}`
}

const buildPublicUploadUrl = (req, folder, filename) => {
  if (!filename) return null
  const relativePath = buildPublicUploadPath(folder, filename)
  return ensureAbsoluteUrl(req, relativePath)
}

module.exports = {
  createOptionalImageUploadMiddleware,
  buildPublicUploadPath,
  buildPublicUploadUrl,
  ensureAbsoluteUrl,
  ensureImagesRelativePath,
  resolveUploadBasePath
}
