const express = require('express')
const multer = require('multer')
const { z } = require('zod')
const { nanoid } = require('nanoid')
const {
  findTierListById,
  listPublicTierLists,
  listFavoriteTierLists,
  listUserTierLists,
  deleteTierList,
  saveTierList,
  createCustomItem,
  createTemplateRequest,
  findUserById,
  findTopicByIdentifier,
  favoriteTierList,
  unfavoriteTierList,
  duplicateTierListForUser,
} = require('../db')
const { requireAuth } = require('../middleware/auth')
const { createMemoryUpload, writeOptimizedImage } = require('../lib/image-storage')

const router = express.Router()
const FREEFORM_TOPIC_ID = 'freeform'
const FREEFORM_DEFAULT_TITLE = '직접 티어표 만들기'

function normalizePoolItem(item) {
  if (!item || item.origin !== 'template' || typeof item.src !== 'string') return item
  if (item.src.startsWith('/uploads/')) return item

  try {
    const url = new URL(item.src)
    if (url.pathname.startsWith('/uploads/')) {
      return { ...item, src: url.pathname }
    }
  } catch (e) {
    return item
  }

  return item
}

function normalizeTierList(tierList) {
  return {
    ...tierList,
    pool: Array.isArray(tierList.pool) ? tierList.pool.map(normalizePoolItem) : [],
  }
}

function getCustomTemplateItems(tierList) {
  const seen = new Set()
  return (tierList?.pool || []).filter((item) => {
    if (!item?.id || item.origin !== 'custom' || seen.has(item.id)) return false
    seen.add(item.id)
    return true
  })
}

const upload = createMemoryUpload(multer, { fileSize: 6 * 1024 * 1024 })
const thumbnailUpload = createMemoryUpload(multer, { fileSize: 8 * 1024 * 1024 })

const templateRequestSchema = z.object({
  type: z.enum(['create', 'update']),
  sourceTierListId: z.string().max(64).optional().default(''),
  topicId: z.string().min(1).max(120).optional(),
  requestTitle: z.string().trim().min(1).max(120),
  requestDescription: z.string().trim().min(1).max(1000),
  thumbnailSrc: z.string().max(255).optional().default(''),
  isPublic: z.boolean().optional().default(false),
  showCharacterNames: z.boolean().optional().default(false),
  groups: z.array(
    z.object({
      id: z.string().min(1),
      name: z.string().min(1).max(16),
      itemIds: z.array(z.string()).optional().default([]),
}).passthrough().superRefine((value, ctx) => {
  if (!value.topicId) {
    ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'topicId_required', path: ['topicId'] })
  }
})
  ),
  boardItems: z.array(
    z.object({
      id: z.string().min(1),
      src: z.string().min(1),
      label: z.string().min(1).max(60),
      origin: z.enum(['template', 'custom']).default('template'),
    })
  ),
})

const tierListUpsertSchema = z.object({
  id: z.string().optional(),
  topicId: z.string().min(1).optional(),
  title: z.string().min(1).max(120),
  thumbnailSrc: z.string().max(255).optional().default(''),
  description: z.string().max(1000).optional().default(''),
  isPublic: z.boolean().default(false),
  showCharacterNames: z.boolean().optional().default(false),
  iconSize: z.number().int().min(48).max(112).optional().default(80),
  sourceTierListId: z.string().max(64).optional().default(''),
  sourceSnapshotTitle: z.string().max(120).optional().default(''),
  sourceSnapshotAuthor: z.string().max(120).optional().default(''),
  groups: z.array(
    z.object({
      id: z.string().min(1),
      name: z.string().min(1).max(16),
      itemIds: z.array(z.string()).optional().default([]),
    }).passthrough()
  ),
  pool: z.array(
    z.object({
      id: z.string().min(1),
      src: z.string().min(1),
      label: z.string().min(1).max(60),
      origin: z.enum(['template', 'custom']).default('template'),
    })
  ),
}).superRefine((value, ctx) => {
  if (!value.topicId) {
    ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'topicId_required', path: ['topicId'] })
  }
})

router.get('/public', async (req, res) => {
  const topicId = typeof req.query.topicId === 'string' ? req.query.topicId : ''
  const queryText = typeof req.query.q === 'string' ? req.query.q : ''
  const result = await listPublicTierLists(topicId, req.session?.userId || '', queryText)
  res.json(result)
})

router.get('/me', requireAuth, async (req, res) => {
  const lists = await listUserTierLists(req.session.userId)
  res.json({ tierLists: lists })
})

router.get('/favorites/me', requireAuth, async (req, res) => {
  const queryText = typeof req.query.q === 'string' ? req.query.q : ''
  const sort = typeof req.query.sort === 'string' ? req.query.sort : 'favorited'
  const lists = await listFavoriteTierLists(req.session.userId, { queryText, sort })
  res.json({ tierLists: lists })
})

router.get('/:id', async (req, res) => {
  const t = await findTierListById(req.params.id, req.session?.userId || '')
  if (!t) return res.status(404).json({ error: 'not_found' })
  if (!t.isPublic) {
    if (!req.session?.userId) return res.status(403).json({ error: 'forbidden' })
    const currentUser = req.session.userId === t.authorId ? { isAdmin: false } : await findUserById(req.session.userId)
    if (req.session.userId !== t.authorId && !currentUser?.isAdmin) return res.status(403).json({ error: 'forbidden' })
  }
  res.json({ tierList: normalizeTierList(t) })
})

router.post('/:id/duplicate', requireAuth, async (req, res) => {
  const tierList = await findTierListById(req.params.id, req.session.userId)
  if (!tierList) return res.status(404).json({ error: 'not_found' })
  if (!tierList.isPublic && tierList.authorId !== req.session.userId) return res.status(403).json({ error: 'forbidden' })

  const duplicated = await duplicateTierListForUser({ tierList, targetUserId: req.session.userId })
  res.json({ tierList: normalizeTierList(duplicated) })
})

router.delete('/:id', requireAuth, async (req, res) => {
  const tierList = await findTierListById(req.params.id, req.session.userId)
  if (!tierList) return res.status(404).json({ error: 'not_found' })
  if (tierList.authorId !== req.session.userId) return res.status(403).json({ error: 'forbidden' })

  await deleteTierList(tierList.id)
  res.json({ ok: true })
})

router.post('/:id/favorite', requireAuth, async (req, res) => {
  const tierList = await findTierListById(req.params.id, req.session.userId)
  if (!tierList) return res.status(404).json({ error: 'not_found' })
  if (!tierList.isPublic && tierList.authorId !== req.session.userId) return res.status(403).json({ error: 'forbidden' })

  await favoriteTierList({ userId: req.session.userId, tierListId: tierList.id })
  const updated = await findTierListById(tierList.id, req.session.userId)
  res.json({ tierList: normalizeTierList(updated) })
})

router.delete('/:id/favorite', requireAuth, async (req, res) => {
  const tierList = await findTierListById(req.params.id, req.session.userId)
  if (!tierList) return res.status(404).json({ error: 'not_found' })

  await unfavoriteTierList({ userId: req.session.userId, tierListId: tierList.id })
  const updated = await findTierListById(tierList.id, req.session.userId)
  res.json({ tierList: normalizeTierList(updated) })
})

router.post('/custom-items', requireAuth, upload.single('image'), async (req, res) => {
  if (!req.file) return res.status(400).json({ error: 'file_required' })

  const schema = z.object({ label: z.string().trim().min(1).max(60) })
  const parsed = schema.safeParse(req.body)
  if (!parsed.success) return res.status(400).json({ error: 'bad_request' })

  const optimized = await writeOptimizedImage({
    file: req.file,
    directory: 'custom',
    width: 512,
    height: 512,
    fit: 'inside',
    quality: 84,
  })

  const item = await createCustomItem({
    id: nanoid(),
    ownerId: req.session.userId,
    src: optimized.src,
    label: parsed.data.label,
  })

  res.json({ item })
})

router.post('/thumbnail', requireAuth, thumbnailUpload.single('thumbnail'), async (req, res) => {
  if (!req.file) return res.status(400).json({ error: 'file_required' })

  const optimized = await writeOptimizedImage({
    file: req.file,
    directory: 'tierlists',
    width: 1280,
    height: 1280,
    fit: 'inside',
    quality: 84,
  })

  res.json({ thumbnailSrc: optimized.src })
})

router.post('/template-request', requireAuth, async (req, res) => {
  const parsed = templateRequestSchema.safeParse(req.body)
  if (!parsed.success) return res.status(400).json({ error: 'bad_request' })

  const payload = parsed.data
  const topic = await findTopicByIdentifier(payload.topicId)
  if (!topic) return res.status(404).json({ error: 'not_found' })
  const normalizedBoardItems = payload.boardItems.map(normalizePoolItem)
  const customItems = normalizedBoardItems.filter((item) => item?.origin === 'custom')
  if (!customItems.length) return res.status(400).json({ error: 'custom_items_required' })

  if (payload.type === 'create') {
    if (topic.id !== FREEFORM_TOPIC_ID) return res.status(400).json({ error: 'freeform_required' })
  } else if (topic.id === FREEFORM_TOPIC_ID) {
    return res.status(400).json({ error: 'topic_template_required' })
  }

  let sourceTierList = null
  if (payload.sourceTierListId) {
    sourceTierList = await findTierListById(payload.sourceTierListId, req.session.userId)
    if (!sourceTierList) return res.status(404).json({ error: 'not_found' })
    if (sourceTierList.authorId !== req.session.userId) return res.status(403).json({ error: 'forbidden' })
  }

  if (!payload.sourceTierListId) return res.status(400).json({ error: 'source_tierlist_required' })

  try {
    const request = await createTemplateRequest({
      id: nanoid(),
      type: payload.type,
      requesterId: req.session.userId,
      sourceTierListId: sourceTierList?.id || '',
      sourceTopicId: topic.id,
      targetTopicId: payload.type === 'update' ? topic.id : '',
      title: payload.requestTitle,
      description: payload.requestDescription,
      thumbnailSrc: payload.thumbnailSrc || '',
      items: customItems,
      groups: payload.groups,
      boardItems: normalizedBoardItems,
      showCharacterNames: !!payload.showCharacterNames,
    })
    return res.json({ request })
  } catch (e) {
    if (e?.code === 'TEMPLATE_REQUEST_EXISTS') {
      return res.status(409).json({ error: 'template_request_exists' })
    }
    throw e
  }
})

router.post('/', requireAuth, async (req, res) => {
  const parsed = tierListUpsertSchema.safeParse(req.body)
  if (!parsed.success) return res.status(400).json({ error: 'bad_request' })
  const payload = parsed.data
  const topic = await findTopicByIdentifier(payload.topicId)
  if (!topic) return res.status(404).json({ error: 'not_found' })
  const normalizedPool = payload.pool.map(normalizePoolItem)

  let existing = null
  if (payload.id) existing = await findTierListById(payload.id)

  if (existing) {
    if (existing.authorId !== req.session.userId) return res.status(403).json({ error: 'forbidden' })
    const updated = await saveTierList({
      id: existing.id,
      authorId: existing.authorId,
      topicId: existing.topicId,
      title: payload.title,
      thumbnailSrc: payload.thumbnailSrc || '',
      description: payload.description || '',
      isPublic: !!payload.isPublic,
      showCharacterNames: !!payload.showCharacterNames,
      iconSize: Number(payload.iconSize || 80),
      sourceTierListId: payload.sourceTierListId || existing.sourceTierListId || '',
      sourceSnapshotTitle: payload.sourceSnapshotTitle || existing.sourceSnapshotTitle || '',
      sourceSnapshotAuthor: payload.sourceSnapshotAuthor || existing.sourceSnapshotAuthor || '',
      groups: payload.groups,
      pool: normalizedPool,
    })
    return res.json({ tierList: normalizeTierList(updated) })
  }

  const created = await saveTierList({
    id: nanoid(),
    authorId: req.session.userId,
    topicId: topic.id,
    title: payload.title,
    thumbnailSrc: payload.thumbnailSrc || '',
    description: payload.description || '',
    isPublic: !!payload.isPublic,
    showCharacterNames: !!payload.showCharacterNames,
    iconSize: Number(payload.iconSize || 80),
    sourceTierListId: payload.sourceTierListId || '',
    sourceSnapshotTitle: payload.sourceSnapshotTitle || '',
    sourceSnapshotAuthor: payload.sourceSnapshotAuthor || '',
    groups: payload.groups,
    pool: normalizedPool,
  })
  res.json({ tierList: normalizeTierList(created) })
})

module.exports = router
