'use server'

import { revalidatePath } from 'next/cache'
import { cookies } from 'next/headers'
import { getIronSession } from 'iron-session'
import { z } from 'zod'
import { prisma } from '@/lib/prisma'
import { SessionData, sessionOptions } from '@/lib/session'
import { productAccessFilter } from '@/lib/product-access'
import { generateNextPbiCode, generateNextStoryCode } from '@/lib/code-server'
import { enforceUserRateLimit } from '@/lib/rate-limit'

async function getSession() {
  return getIronSession<SessionData>(await cookies(), sessionOptions)
}

export async function createTodoAction(_prevState: unknown, formData: FormData) {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd' }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }

  const limited = enforceUserRateLimit('create-todo', session.userId)
  if (limited) return limited

  const title = (formData.get('title') as string)?.trim()
  const description = (formData.get('description') as string)?.trim() || null
  const raw = (formData.get('productId') as string)?.trim()
  const productId = (raw && raw !== 'all') ? raw : null

  if (!title) return { error: 'Titel is verplicht' }
  if (description && description.length > 2000) return { error: 'Beschrijving is langer dan 2000 tekens' }

  if (productId) {
    const product = await prisma.product.findFirst({
      where: { id: productId, ...productAccessFilter(session.userId), archived: false },
    })
    if (!product) return { error: 'Product niet gevonden' }
  }

  await prisma.todo.create({
    data: { user_id: session.userId, product_id: productId, title, description },
  })
  revalidatePath('/todos')
  return { success: true }
}

export async function toggleTodoAction(id: string, done: boolean) {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd' }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }

  const todo = await prisma.todo.findFirst({ where: { id, user_id: session.userId } })
  if (!todo) return { error: 'Todo niet gevonden' }

  await prisma.todo.update({ where: { id }, data: { done } })
  revalidatePath('/todos')
  return { success: true }
}

export async function archiveCompletedTodosAction() {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd' }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }

  await prisma.todo.updateMany({
    where: { user_id: session.userId, done: true, archived: false },
    data: { archived: true },
  })
  revalidatePath('/todos')
  return { success: true }
}

export async function updateTodoAction(_prevState: unknown, formData: FormData) {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd' }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }

  const id = (formData.get('id') as string)?.trim()
  const title = (formData.get('title') as string)?.trim()
  const description = (formData.get('description') as string)?.trim() || null
  const raw = (formData.get('productId') as string)?.trim()
  const productId = raw || null
  const done = formData.get('done') === 'on'

  if (!id) return { error: 'Ongeldige todo' }
  if (!title) return { error: 'Titel is verplicht' }
  if (description && description.length > 2000) return { error: 'Beschrijving is langer dan 2000 tekens' }

  const todo = await prisma.todo.findFirst({
    where: { id, user_id: session.userId },
  })
  if (!todo) return { error: 'Todo niet gevonden' }

  if (productId) {
    const product = await prisma.product.findFirst({
      where: { id: productId, ...productAccessFilter(session.userId), archived: false },
    })
    if (!product) return { error: 'Product niet gevonden' }
  }

  await prisma.todo.update({
    where: { id },
    data: { title, description, product_id: productId, done },
  })
  revalidatePath('/todos')
  return { success: true }
}

export async function archiveSelectedTodosAction(ids: string[]) {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd' }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }
  if (!ids.length) return { error: 'Geen todos geselecteerd' }

  const owned = await prisma.todo.findMany({
    where: { id: { in: ids }, user_id: session.userId },
    select: { id: true },
  })
  if (owned.length !== ids.length) return { error: 'Ongeldige selectie' }

  await prisma.todo.updateMany({
    where: { id: { in: ids }, user_id: session.userId },
    data: { archived: true },
  })
  revalidatePath('/todos')
  return { success: true }
}

const promotePbiSchema = z.object({
  todoId: z.string(),
  productId: z.string(),
  title: z.string().min(1).max(200),
  priority: z.coerce.number().int().min(1).max(4),
})

export async function promoteTodoToPbiAction(_prevState: unknown, formData: FormData) {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd' }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }

  const parsed = promotePbiSchema.safeParse({
    todoId: formData.get('todoId'),
    productId: formData.get('productId'),
    title: formData.get('title'),
    priority: formData.get('priority'),
  })
  if (!parsed.success) return { error: parsed.error.flatten().fieldErrors }

  const product = await prisma.product.findFirst({
    where: { id: parsed.data.productId, ...productAccessFilter(session.userId) },
  })
  if (!product) return { error: 'Product niet gevonden' }

  const todo = await prisma.todo.findFirst({
    where: { id: parsed.data.todoId, user_id: session.userId },
  })
  if (!todo) return { error: 'Todo niet gevonden' }

  const last = await prisma.pbi.findFirst({
    where: { product_id: parsed.data.productId, priority: parsed.data.priority },
    orderBy: { sort_order: 'desc' },
  })

  const pbiCode = await generateNextPbiCode(parsed.data.productId)

  await prisma.$transaction([
    prisma.pbi.create({
      data: {
        product_id: parsed.data.productId,
        code: pbiCode,
        title: parsed.data.title,
        priority: parsed.data.priority,
        sort_order: (last?.sort_order ?? 0) + 1.0,
      },
    }),
    prisma.todo.deleteMany({ where: { id: parsed.data.todoId, user_id: session.userId } }),
  ])

  revalidatePath('/todos')
  revalidatePath(`/products/${parsed.data.productId}`)
  return { success: true }
}

const promoteStorySchema = z.object({
  todoId: z.string(),
  productId: z.string(),
  pbiId: z.string(),
  title: z.string().min(1).max(200),
  priority: z.coerce.number().int().min(1).max(4),
})

export async function promoteTodoToStoryAction(_prevState: unknown, formData: FormData) {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd' }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }

  const parsed = promoteStorySchema.safeParse({
    todoId: formData.get('todoId'),
    productId: formData.get('productId'),
    pbiId: formData.get('pbiId'),
    title: formData.get('title'),
    priority: formData.get('priority'),
  })
  if (!parsed.success) return { error: parsed.error.flatten().fieldErrors }

  const todo = await prisma.todo.findFirst({
    where: { id: parsed.data.todoId, user_id: session.userId },
  })
  if (!todo) return { error: 'Todo niet gevonden' }

  const pbi = await prisma.pbi.findFirst({
    where: { id: parsed.data.pbiId, product: productAccessFilter(session.userId) },
  })
  if (!pbi) return { error: 'PBI niet gevonden' }
  if (todo.product_id !== null && todo.product_id !== pbi.product_id) return { error: 'Todo hoort niet bij dit product' }

  const last = await prisma.story.findFirst({
    where: { pbi_id: parsed.data.pbiId, priority: parsed.data.priority },
    orderBy: { sort_order: 'desc' },
  })

  const storyCode = await generateNextStoryCode(pbi.product_id)

  await prisma.$transaction([
    prisma.story.create({
      data: {
        pbi_id: parsed.data.pbiId,
        product_id: pbi.product_id,
        code: storyCode,
        title: parsed.data.title,
        priority: parsed.data.priority,
        sort_order: (last?.sort_order ?? 0) + 1.0,
        status: 'OPEN',
      },
    }),
    prisma.todo.deleteMany({ where: { id: parsed.data.todoId, user_id: session.userId } }),
  ])

  revalidatePath('/todos')
  revalidatePath(`/products/${pbi.product_id}`)
  return { success: true }
}

// M12: promote a Todo into a DRAFT Idea. Anders dan Todo→PBI/Story (die de
// todo deleteert) ARCHIVEREN we de todo hier — het idee houdt zelf de
// planningsgeschiedenis bij, en de archived todo bewaart het oorspronkelijke
// vertrekpunt.
export async function promoteTodoToIdeaAction(todoId: string): Promise<
  { success: true; idea_id: string; idea_code: string } | { error: string; code?: number }
> {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd', code: 401 }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus', code: 403 }

  if (!todoId) return { error: 'todoId is verplicht', code: 422 }

  const todo = await prisma.todo.findFirst({
    where: { id: todoId, user_id: session.userId },
    select: { id: true, title: true, description: true, product_id: true, archived: true },
  })
  if (!todo) return { error: 'Todo niet gevonden', code: 404 }
  if (todo.archived) return { error: 'Todo is al gearchiveerd', code: 422 }

  const userId = session.userId
  // Lazy-import om dit server-only bestand niet te dwingen in een client bundle.
  const { nextIdeaCode } = await import('@/lib/idea-code-server')

  const idea = await prisma.$transaction(async (tx) => {
    const code = await nextIdeaCode(userId, tx)
    const created = await tx.idea.create({
      data: {
        user_id: userId,
        product_id: todo.product_id,
        code,
        title: todo.title,
        description: todo.description ?? null,
        status: 'DRAFT',
      },
      select: { id: true, code: true },
    })
    await tx.todo.update({ where: { id: todoId }, data: { archived: true } })
    await tx.ideaLog.create({
      data: {
        idea_id: created.id,
        type: 'NOTE',
        content: `Promoted from Todo ${todoId}`,
        metadata: { source_todo_id: todoId },
      },
    })
    return created
  })

  revalidatePath('/ideas')
  revalidatePath('/todos')
  return { success: true, idea_id: idea.id, idea_code: idea.code }
}

export async function updateRolesAction(roles: string[]) {
  const session = await getSession()
  if (!session.userId) return { error: 'Niet ingelogd' }
  if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }

  const validRoles = ['PRODUCT_OWNER', 'SCRUM_MASTER', 'DEVELOPER']
  const filtered = roles.filter(r => validRoles.includes(r))
  if (filtered.length === 0) return { error: 'Minimaal één rol is verplicht' }

  await prisma.$transaction([
    prisma.userRole.deleteMany({ where: { user_id: session.userId } }),
    prisma.userRole.createMany({
      data: filtered.map(role => ({ user_id: session.userId, role: role as 'PRODUCT_OWNER' | 'SCRUM_MASTER' | 'DEVELOPER' })),
    }),
  ])

  revalidatePath('/settings')
  return { success: true }
}
