import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createEvent, mockSuccessReadBody } from './setup'
import fs from 'fs/promises'

vi.mock('../server/utils/auth.js', () => ({
  getUserFromToken: vi.fn(),
  hasAnyRole: vi.fn((user, ...roles) => {
    if (!user) return false
    const userRoles = Array.isArray(user.roles) ? user.roles : (user.role ? [user.role] : [])
    return roles.some(r => userRoles.includes(r))
  })
}))

vi.mock('multer', () => {
  const single = vi.fn((field) => (req, _res, cb) => {
    if (req.__mockMulterError) {
      cb(req.__mockMulterError)
      return
    }
    req.file = req.__mockFile || null
    req.body = req.body || {}
    cb(null)
  })

  const multerFn = vi.fn(() => ({ single }))
  const diskStorage = vi.fn(() => ({}))
  multerFn.diskStorage = diskStorage

  return {
    default: multerFn,
    diskStorage
  }
})

vi.mock('child_process', () => ({
  exec: vi.fn()
}))

vi.mock('util', () => ({
  promisify: () => () => Promise.resolve({
    stdout: `§ 1 Name und Sitz
Der Verein führt den Namen Harheimer TC.

§ 2 Zweck
Der Verein verfolgt ausschließlich und unmittelbar gemeinnützige Zwecke.

§ 3 Mitgliedschaft
(1) Mitglied kann jede natürliche Person werden.
(2) Über die Aufnahme entscheidet der Vorstand.

§ 4 Beiträge
Die Mitglieder zahlen Beiträge nach Maßgabe der Beitragsordnung.

§ 5 Vorstand
Der Vorstand besteht aus dem Vorsitzenden, dem Schriftführer und dem Kassenwart.

§ 6 Schlussbestimmungen
Diese Satzung tritt mit Beschluss der Mitgliederversammlung in Kraft.

Zusätzlicher Satzungstext zur Plausibilitätsprüfung.
Zusätzlicher Satzungstext zur Plausibilitätsprüfung.
Zusätzlicher Satzungstext zur Plausibilitätsprüfung.
Zusätzlicher Satzungstext zur Plausibilitätsprüfung.
Zusätzlicher Satzungstext zur Plausibilitätsprüfung.
`,
    stderr: ''
  })
}))

vi.mock('../server/utils/upload-validation.js', () => ({
  assertPdfMagicHeader: vi.fn().mockResolvedValue(undefined)
}))

import saveCsvHandler from '../server/api/cms/save-csv.post.js'
import uploadSpielplanHandler from '../server/api/cms/upload-spielplan-pdf.post.js'
import satzungUploadHandler from '../server/api/cms/satzung-upload.post.js'

const { getUserFromToken } = await import('../server/utils/auth.js')

describe('CMS File Endpoints', () => {
  beforeEach(() => {
    vi.restoreAllMocks()
    vi.clearAllMocks()
    getUserFromToken.mockReset()
    getUserFromToken.mockResolvedValue({ id: 'admin', role: 'admin' })
  })

  describe('POST /api/cms/save-csv', () => {
    it('validiert Eingaben', async () => {
      const event = createEvent({ cookies: { auth_token: 'token' } })
      mockSuccessReadBody({})

      await expect(saveCsvHandler(event)).rejects.toMatchObject({ statusCode: 400 })
    })

    it('speichert erlaubte Datei', async () => {
      const event = createEvent({ cookies: { auth_token: 'token' } })
      mockSuccessReadBody({ filename: 'mannschaften.csv', content: 'data' })
      vi.spyOn(fs, 'mkdir').mockResolvedValue(undefined)
      vi.spyOn(fs, 'writeFile').mockResolvedValue(undefined)
      vi.spyOn(fs, 'rename').mockResolvedValue(undefined)
      vi.spyOn(fs, 'stat').mockResolvedValue({ size: Buffer.byteLength('data', 'utf8') } as any)

      const response = await saveCsvHandler(event)
      expect(response.success).toBe(true)
      expect(fs.writeFile).toHaveBeenCalled()
    })

    it('erlaubt vorstand beim CSV-Speichern', async () => {
      const event = createEvent({ cookies: { auth_token: 'token' } })
      mockSuccessReadBody({ filename: 'spielplan.csv', content: 'kopf;wert' })
      vi.spyOn(fs, 'mkdir').mockResolvedValue(undefined)
      vi.spyOn(fs, 'writeFile').mockResolvedValue(undefined)
      vi.spyOn(fs, 'rename').mockResolvedValue(undefined)
      vi.spyOn(fs, 'stat').mockResolvedValue({ size: Buffer.byteLength('kopf;wert', 'utf8') } as any)
      getUserFromToken.mockResolvedValue({ id: 'vorstand', role: 'vorstand' })

      const response = await saveCsvHandler(event)
      expect(response.success).toBe(true)
    })
  })

  describe('POST /api/cms/upload-spielplan-pdf', () => {
    it('erfordert Authorization Header', async () => {
      const event = createEvent({ method: 'POST' })
      event.node.req.__mockFile = { filename: 'file.pdf', originalname: 'orig.pdf', path: 'tmp', mimetype: 'application/pdf' }
      event.node.req.body = { type: 'gesamt' }
      getUserFromToken.mockResolvedValue(null)

      await expect(uploadSpielplanHandler(event)).rejects.toMatchObject({ statusCode: 401 })
    })

    it('lädt PDF hoch und gibt Erfolg zurück', async () => {
      const event = createEvent({ method: 'POST', headers: { authorization: 'Bearer valid-token' } })
      event.node.req.__mockFile = { filename: 'spielplan_gesamt.pdf', originalname: 'orig.pdf', path: 'tmp', mimetype: 'application/pdf' }
      event.node.req.body = { type: 'gesamt' }
      getUserFromToken.mockResolvedValue({ id: 'admin', role: 'admin' })

      const response = await uploadSpielplanHandler(event)
      expect(response.success).toBe(true)
      expect(response.filename).toBeDefined()
    })
  })

  describe('POST /api/cms/satzung-upload', () => {
    it('verarbeitet hochgeladene Satzung', async () => {
      const event = createEvent({ method: 'POST', cookies: { auth_token: 'token' } })
      event.node.req.__mockFile = { path: 'public/documents/satzung.pdf', filename: 'satzung.pdf', originalname: 'satzung.pdf', mimetype: 'application/pdf' }
      vi.spyOn(fs, 'readFile').mockResolvedValueOnce(JSON.stringify({ seiten: {}, vorstand: { vorsitzender: { email: '' }, schriftfuehrer: { email: '' } } }))
      vi.spyOn(fs, 'writeFile').mockResolvedValue(undefined)
      getUserFromToken.mockResolvedValue({ id: 'admin', role: 'admin' })

      const response = await satzungUploadHandler(event)
      expect(response.success).toBe(true)
      expect(fs.writeFile).toHaveBeenCalled()
    })
  })
})
