import express from 'express'
import cors from 'cors'
import { fileURLToPath } from 'url'
import { promises as fs } from 'fs'
import path from 'path'
import crypto from 'crypto'
import multer from 'multer'

const app = express()
const port = process.env.PORT || 4001
const adminToken = process.env.ADMIN_TOKEN || 'timo'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const dataDir = path.join(__dirname, 'data')
const dataPath = path.join(dataDir, 'events.json')
const uploadsDir = path.join(__dirname, 'uploads')

await fs.mkdir(uploadsDir, { recursive: true })

const storage = multer.diskStorage({
  destination: (req, file, cb) => cb(null, uploadsDir),
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname || '') || '.png'
    const base = (file.originalname || 'upload')
      .replace(/[^a-z0-9]+/gi, '-')
      .replace(/^-+|-+$/g, '')
      .toLowerCase() || 'upload'
    const unique = `${base}-${Date.now()}${ext}`
    cb(null, unique)
  }
})

const allowedMimeTypes = new Set([
  'image/png',
  'image/jpeg',
  'image/gif',
  'image/webp',
  'image/svg+xml'
])

const upload = multer({
  storage,
  limits: { fileSize: 5 * 1024 * 1024 },
  fileFilter: (req, file, cb) => {
    if (allowedMimeTypes.has(file.mimetype)) {
      cb(null, true)
    } else {
      cb(new Error('Only image uploads are allowed'))
    }
  }
})

async function ensureDataFile() {
  try {
    await fs.access(dataPath)
  } catch {
    await fs.mkdir(dataDir, { recursive: true })
    await fs.writeFile(dataPath, '[]', 'utf-8')
  }
}

function slugify(text) {
  return text
    .toString()
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
}

async function readEvents() {
  await ensureDataFile()
  const raw = await fs.readFile(dataPath, 'utf-8')
  try {
    return JSON.parse(raw)
  } catch (error) {
    console.error('Failed to parse events file, resetting to []', error)
    await fs.writeFile(dataPath, '[]', 'utf-8')
    return []
  }
}

async function writeEvents(events) {
  await fs.writeFile(dataPath, JSON.stringify(events, null, 2), 'utf-8')
}

function requireAuth(req, res, next) {
  const token = req.header('x-admin-token')
  if (!token || token !== adminToken) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  return next()
}

function asyncHandler(fn) {
  return (req, res, next) => {
    Promise.resolve(fn(req, res, next)).catch(next)
  }
}

function buildEventPayload(input, base = {}) {
  const allowed = ['title', 'description', 'date', 'time', 'location', 'category', 'image']
  const payload = { ...base }
  for (const key of allowed) {
    if (key in input && input[key] !== undefined) {
      payload[key] = typeof input[key] === 'string' ? input[key].trim() : input[key]
    }
  }
  return payload
}

app.use(cors())
app.use(express.json({ limit: '1mb' }))
app.use('/uploads', express.static(uploadsDir))

app.get('/api/health', (req, res) => {
  res.json({ status: 'ok' })
})

app.get('/api/events', asyncHandler(async (req, res) => {
  const events = await readEvents()
  const sorted = events.slice().sort((a, b) => new Date(a.date) - new Date(b.date))
  res.json(sorted)
}))

app.get('/api/events/:slug', asyncHandler(async (req, res) => {
  const events = await readEvents()
  const event = events.find(e => e.slug === req.params.slug)
  if (!event) {
    return res.status(404).json({ error: 'Event not found' })
  }
  res.json(event)
}))

app.post('/api/events', requireAuth, asyncHandler(async (req, res) => {
  const data = buildEventPayload(req.body)
  if (!data.title || !data.date) {
    return res.status(400).json({ error: 'title and date are required' })
  }

  const events = await readEvents()
  const baseSlug = slugify(req.body.slug || data.title || '') || `event-${Date.now()}`
  let uniqueSlug = baseSlug
  let suffix = 1
  while (events.some(event => event.slug === uniqueSlug)) {
    uniqueSlug = `${baseSlug}-${suffix++}`
  }

  const now = new Date().toISOString()
  const newEvent = {
    id: crypto.randomUUID(),
    slug: uniqueSlug,
    createdAt: now,
    updatedAt: now,
    ...data,
  }

  events.push(newEvent)
  await writeEvents(events)
  res.status(201).json(newEvent)
}))

app.patch('/api/events/:slug', requireAuth, asyncHandler(async (req, res) => {
  const events = await readEvents()
  const index = events.findIndex(event => event.slug === req.params.slug)
  if (index === -1) {
    return res.status(404).json({ error: 'Event not found' })
  }

  const event = events[index]
  const updated = buildEventPayload(req.body, event)
  let slugToUse = event.slug
  if (req.body.slug && req.body.slug !== event.slug) {
    const requestedSlug = slugify(req.body.slug)
    let uniqueSlug = requestedSlug || event.slug
    let suffix = 1
    while (events.some((e, i) => i !== index && e.slug === uniqueSlug)) {
      uniqueSlug = `${requestedSlug}-${suffix++}`
    }
    slugToUse = uniqueSlug
  }

  const merged = {
    ...event,
    ...updated,
    slug: slugToUse,
    updatedAt: new Date().toISOString(),
  }

  events[index] = merged
  await writeEvents(events)
  res.json(merged)
}))

app.delete('/api/events/:slug', requireAuth, asyncHandler(async (req, res) => {
  const events = await readEvents()
  const index = events.findIndex(event => event.slug === req.params.slug)
  if (index === -1) {
    return res.status(404).json({ error: 'Event not found' })
  }

  const [removed] = events.splice(index, 1)
  await writeEvents(events)
  res.json({ success: true, removed })
}))

app.post('/api/uploads', requireAuth, upload.single('file'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'No file uploaded' })
  }
  const relativeUrl = `/uploads/${req.file.filename}`
  const absoluteUrl = `${req.protocol}://${req.get('host')}${relativeUrl}`
  res.status(201).json({ url: absoluteUrl, path: relativeUrl })
})

app.get('/api/admin/verify', requireAuth, (req, res) => {
  res.json({ ok: true })
})

app.use((err, req, res, next) => {
  if (err instanceof multer.MulterError) {
    return res.status(400).json({ error: err.message })
  }
  if (err && err.message === 'Only image uploads are allowed') {
    return res.status(400).json({ error: err.message })
  }
  console.error(err)
  res.status(500).json({ error: 'Internal server error' })
})

app.listen(port, () => {
  console.log(`Events API listening on port ${port}`)
})
