import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/db'
import { getSession } from '@/lib/auth'
import { uploadFile } from '@/lib/minio'

async function getTenantId() {
  const user = await getSession()
  if (!user) return { error: 'Nicht autorisiert', status: 401 }
  if (user.role !== 'TENANT_ADMIN' && user.role !== 'SERVER_ADMIN') {
    return { error: 'Keine Berechtigung', status: 403 }
  }
  if (!user.tenantId) return { error: 'Kein Mandant zugeordnet', status: 400 }
  return { tenantId: user.tenantId }
}

async function ensureTables() {
  // ─── Create tables (idempotent) ───
  await prisma.$executeRawUnsafe(`
    CREATE TABLE IF NOT EXISTS tenant_symbols (
      id TEXT PRIMARY KEY DEFAULT gen_random_uuid(),
      "isActive" BOOLEAN NOT NULL DEFAULT true,
      "tenantId" TEXT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
      "iconId" TEXT REFERENCES icon_assets(id) ON DELETE SET NULL,
      "name" TEXT,
      "svgPath" TEXT,
      "isUploaded" BOOLEAN NOT NULL DEFAULT false,
      "categoryId" TEXT,
      "migratedFromIconId" TEXT,
      "customName" TEXT,
      "sortOrder" INTEGER,
      "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
      "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
    )
  `)
  await prisma.$executeRawUnsafe(`
    CREATE TABLE IF NOT EXISTS tenant_categories (
      id TEXT PRIMARY KEY DEFAULT gen_random_uuid(),
      "name" TEXT NOT NULL,
      "description" TEXT,
      "sortOrder" INTEGER NOT NULL DEFAULT 0,
      "isActive" BOOLEAN NOT NULL DEFAULT true,
      "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
      "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
      "tenantId" TEXT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE
    )
  `)

  // ─── Add missing columns (idempotent) ───
  const symbolCols = [
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "name" TEXT`,
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "svgPath" TEXT`,
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "isUploaded" BOOLEAN NOT NULL DEFAULT false`,
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "categoryId" TEXT`,
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "migratedFromIconId" TEXT`,
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "customName" TEXT`,
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "sortOrder" INTEGER`,
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP`,
    `ALTER TABLE tenant_symbols ADD COLUMN IF NOT EXISTS "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP`,
  ]
  for (const sql of symbolCols) {
    try { await prisma.$executeRawUnsafe(sql) } catch (e) { /* ignore */ }
  }

  const catCols = [
    `ALTER TABLE tenant_categories ADD COLUMN IF NOT EXISTS "description" TEXT`,
    `ALTER TABLE tenant_categories ADD COLUMN IF NOT EXISTS "sortOrder" INTEGER NOT NULL DEFAULT 0`,
    `ALTER TABLE tenant_categories ADD COLUMN IF NOT EXISTS "isActive" BOOLEAN NOT NULL DEFAULT true`,
    `ALTER TABLE tenant_categories ADD COLUMN IF NOT EXISTS "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP`,
    `ALTER TABLE tenant_categories ADD COLUMN IF NOT EXISTS "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP`,
  ]
  for (const sql of catCols) {
    try { await prisma.$executeRawUnsafe(sql) } catch (e) { /* ignore */ }
  }
}

// ─── GET ────────────────────────────────────────────────────────────────────

export async function GET(req: NextRequest) {
  try {
    const auth = await getTenantId()
    if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status })
    const { tenantId } = auth

    const { searchParams } = new URL(req.url)
    const grouped = searchParams.get('grouped') !== 'false'

    await ensureTables()

    const tenantSymbols: any[] = await prisma.$queryRawUnsafe(
      `SELECT ts.*, tc.id as "catId", tc.name as "catName", tc."sortOrder" as "catSort"
       FROM tenant_symbols ts
       LEFT JOIN tenant_categories tc ON ts."categoryId" = tc.id
       WHERE ts."tenantId" = $1 AND (ts."isActive" IS NULL OR ts."isActive" = true)
       ORDER BY COALESCE(tc."sortOrder", 9999) ASC, COALESCE(ts."sortOrder", 9999) ASC, COALESCE(ts.name, ts."customName", 'Unbenannt') ASC`,
      tenantId
    )

    const mapped = tenantSymbols.map((ts: any) => ({
      id: ts.id,
      name: ts.name || ts.customName || 'Unbenannt',
      customName: ts.customName,
      svgPath: ts.svgPath,
      categoryId: ts.categoryId,
      categoryName: ts.catName || 'Ohne Kategorie',
      sortOrder: ts.sortOrder,
      isUploaded: ts.isUploaded,
      createdAt: ts.createdAt,
    }))

    if (!grouped) {
      return NextResponse.json({ symbols: mapped })
    }

    // Group by category
    const groupedResult: Record<string, { catId: string | null; catName: string; symbols: any[] }> = {}
    for (const sym of mapped) {
      const key = sym.categoryId || '__none__'
      if (!groupedResult[key]) {
        groupedResult[key] = { catId: sym.categoryId, catName: sym.categoryName, symbols: [] }
      }
      groupedResult[key].symbols.push(sym)
    }

    // Get categories for ordering
    const categories: any[] = await prisma.$queryRawUnsafe(
      `SELECT * FROM tenant_categories WHERE "tenantId" = $1 AND ("isActive" IS NULL OR "isActive" = true) ORDER BY "sortOrder" ASC`,
      tenantId
    )

    const ordered: Array<{ category: { id: string; name: string } | null; symbols: any[] }> = []
    for (const cat of categories) {
      if (groupedResult[cat.id]) {
        ordered.push({ category: { id: cat.id, name: cat.name }, symbols: groupedResult[cat.id].symbols })
        delete groupedResult[cat.id]
      }
    }
    // Append any remaining uncategorized
    for (const entry of Object.values(groupedResult)) {
      ordered.push({ category: null, symbols: entry.symbols })
    }

    return NextResponse.json({ categories: ordered })
  } catch (error) {
    console.error('Error fetching tenant symbols:', error)
    return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
  }
}

// ─── POST ───────────────────────────────────────────────────────────────────

export async function POST(req: NextRequest) {
  try {
    const auth = await getTenantId()
    if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status })
    const { tenantId } = auth

    await ensureTables()

    const contentType = req.headers.get('content-type') || ''

    // Get next sort order
    const maxSort = await prisma.$queryRawUnsafe(
      `SELECT MAX("sortOrder") as maxsort FROM tenant_symbols WHERE "tenantId" = $1`,
      tenantId
    ) as any[]
    const nextSort = (maxSort[0]?.maxsort ?? -1) + 1

    // ─── File Upload ─────────────────────────────────────────────────────────
    if (contentType.includes('multipart/form-data')) {
      const formData = await req.formData()
      const file = formData.get('file') as File | null
      const name = formData.get('name') as string | null
      const categoryId = formData.get('categoryId') as string | null

      if (!file || !name) {
        return NextResponse.json({ error: 'Datei und Name erforderlich' }, { status: 400 })
      }

      const bytes = await file.arrayBuffer()
      const buffer = Buffer.from(bytes)
      const ext = file.name.split('.').pop()?.toLowerCase() || 'svg'
      const mimeType = ext === 'svg' ? 'image/svg+xml' : `image/${ext}`
      const fileKey = `tenant-${tenantId}/symbols/${Date.now()}-${name.replace(/\s+/g, '_').toLowerCase()}.${ext}`

      await uploadFile(fileKey, buffer, mimeType)

      const result = await prisma.$queryRawUnsafe(
        `INSERT INTO tenant_symbols (id, "tenantId", name, "svgPath", "categoryId", "sortOrder", "isUploaded", "createdAt", "updatedAt")
         VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, true, NOW(), NOW())
         RETURNING *`,
        tenantId, name.trim(), fileKey, categoryId || null, nextSort
      ) as any[]
      const symbol = result[0]

      return NextResponse.json({
        id: symbol.id,
        name: symbol.name,
        svgPath: symbol.svgPath,
        categoryId: symbol.categoryId,
        sortOrder: symbol.sortOrder,
        isUploaded: true,
      }, { status: 201 })
    }

    // ─── JSON (from IconAsset or Template) ──────────────────────────────────
    const body = await req.json()
    const { iconId, customName, templateId, categoryId } = body

    // From SymbolTemplate
    if (templateId) {
      const tpl = await prisma.$queryRawUnsafe(
        `SELECT * FROM symbol_templates WHERE id = $1 LIMIT 1`,
        templateId
      ) as any[]
      if (!tpl || tpl.length === 0) {
        return NextResponse.json({ error: 'Template nicht gefunden' }, { status: 404 })
      }
      const t = tpl[0]

      const result = await prisma.$queryRawUnsafe(
        `INSERT INTO tenant_symbols (id, "tenantId", name, "svgPath", "categoryId", "sortOrder", "isUploaded", "createdAt", "updatedAt")
         VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, false, NOW(), NOW())
         RETURNING *`,
        tenantId, t.name, t.svgPath, categoryId || null, nextSort
      ) as any[]
      const symbol = result[0]

      return NextResponse.json({
        id: symbol.id,
        name: symbol.name,
        svgPath: symbol.svgPath,
        categoryId: symbol.categoryId,
        sortOrder: symbol.sortOrder,
        isUploaded: false,
      }, { status: 201 })
    }

    // From IconAsset (legacy path)
    if (!iconId) {
      return NextResponse.json({ error: 'iconId oder templateId erforderlich' }, { status: 400 })
    }

    const icons = await prisma.$queryRawUnsafe(
      `SELECT * FROM icon_assets WHERE id = $1 LIMIT 1`,
      iconId
    ) as any[]
    if (!icons || icons.length === 0) {
      return NextResponse.json({ error: 'Icon nicht gefunden' }, { status: 404 })
    }
    const icon = icons[0]

    const result = await prisma.$queryRawUnsafe(
      `INSERT INTO tenant_symbols (id, "tenantId", "iconId", "customName", name, "svgPath", "categoryId", "sortOrder", "isUploaded", "createdAt", "updatedAt")
       VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, false, NOW(), NOW())
       RETURNING *`,
      tenantId, icon.id, customName || null, customName || icon.name, icon.fileKey, categoryId || null, nextSort
    ) as any[]
    const symbol = result[0]

    return NextResponse.json({
      id: symbol.id,
      iconId: symbol.iconId,
      name: symbol.name,
      customName: symbol.customName,
      svgPath: symbol.svgPath,
      categoryId: symbol.categoryId,
      sortOrder: symbol.sortOrder,
      isUploaded: false,
    }, { status: 201 })
  } catch (error) {
    console.error('Error adding tenant symbol:', error)
    return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
  }
}

// ─── PATCH ──────────────────────────────────────────────────────────────────

export async function PATCH(req: NextRequest) {
  try {
    const auth = await getTenantId()
    if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status })
    const { tenantId } = auth

    const { id, name, customName, categoryId, sortOrder } = await req.json()
    if (!id) return NextResponse.json({ error: 'id erforderlich' }, { status: 400 })

    await ensureTables()

    const updates: string[] = []
    const params: any[] = [id, tenantId]
    if (name !== undefined) { updates.push(`name = $${params.length + 1}`); params.push(name || null); }
    if (customName !== undefined) { updates.push(`"customName" = $${params.length + 1}`); params.push(customName || null); }
    if (categoryId !== undefined) { updates.push(`"categoryId" = $${params.length + 1}`); params.push(categoryId || null); }
    if (sortOrder !== undefined) { updates.push(`"sortOrder" = $${params.length + 1}`); params.push(sortOrder); }
    updates.push(`"updatedAt" = NOW()`)

    const result = await prisma.$queryRawUnsafe(
      `UPDATE tenant_symbols SET ${updates.join(', ')} WHERE id = $1 AND "tenantId" = $2 RETURNING *`,
      ...params
    ) as any[]

    if (!result || result.length === 0) {
      return NextResponse.json({ error: 'Symbol nicht gefunden' }, { status: 404 })
    }

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error('Error updating tenant symbol:', error)
    return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
  }
}

// ─── DELETE ─────────────────────────────────────────────────────────────────

export async function DELETE(req: NextRequest) {
  try {
    const auth = await getTenantId()
    if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status })
    const { tenantId } = auth

    const { id } = await req.json()
    if (!id) return NextResponse.json({ error: 'id erforderlich' }, { status: 400 })

    await ensureTables()

    const result = await prisma.$queryRawUnsafe(
      `DELETE FROM tenant_symbols WHERE id = $1 AND "tenantId" = $2 RETURNING *`,
      id, tenantId
    ) as any[]

    if (!result || result.length === 0) {
      return NextResponse.json({ error: 'Symbol nicht gefunden' }, { status: 404 })
    }

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error('Error deleting tenant symbol:', error)
    return NextResponse.json({ error: 'Interner Fehler' }, { status: 500 })
  }
}
