"use client"

import { createContext, useContext, useState, useCallback, useEffect, type ReactNode } from "react"
import { useSession, signIn, signOut } from "next-auth/react"
import type { User, Ticket, TicketStatus, Room } from "./types"

const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8080/api"

interface AuthContextType {
  user: User | null
  tickets: Ticket[]
  rooms: Room[]
  login: (email: string, password: string) => Promise<boolean>
  register: (user: Omit<User, "id" | "name"> & { firstname: string; lastname: string; password: string; roomIds?: number[] }) => Promise<boolean>
  logout: () => void
  createTicket: (ticket: { roomId: number; title: string; description: string }) => Promise<void>
  updateTicketStatus: (ticketId: number, status: TicketStatus) => Promise<void>
  updateRooms: (roomIds: number[]) => Promise<void>
}

const AuthContext = createContext<AuthContextType | null>(null)

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null)
  const [tickets, setTickets] = useState<Ticket[]>([])
  const [rooms, setRooms] = useState<Room[]>([])
  const [authHeader, setAuthHeader] = useState<string | null>(null)

  // Fetch rooms on mount
  useEffect(() => {
    fetch(`${API_URL}/rooms`)
      .then(res => {
        if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`)
        return res.json()
      })
      .then(data => setRooms(data))
      .catch(err => console.error("Failed to fetch rooms", err))
  }, [])

  const fetchTickets = useCallback(async (auth: string) => {
    try {
      const res = await fetch(`${API_URL}/tickets`, {
        headers: { "Authorization": auth }
      })
      if (res.ok) {
        const data = await res.json()
        setTickets(data)
      }
    } catch (err) {
      console.error("Failed to fetch tickets", err)
    }
  }, [])

  // Sync with NextAuth session
  const { data: session, status } = useSession()

  useEffect(() => {
    if (session?.user && session?.authHeader) {
      // @ts-ignore
      setUser(session.user)
      // @ts-ignore
      setAuthHeader(session.authHeader)
      // @ts-ignore
      fetchTickets(session.authHeader)
    } else if (status === "unauthenticated") {
      setUser(null)
      setAuthHeader(null)
      setTickets([])
    }
  }, [session, status, fetchTickets])

  const login = useCallback(async (email: string, password: string) => {
    // We use next-auth signIn, which calls our authorize callback
    const result = await signIn("credentials", {
      email,
      password,
      redirect: false
    })

    if (result?.ok) {
      // Session update will trigger useEffect
      return true
    }
    return false
  }, [])

  const register = useCallback(async (newUser: any) => {
    const payload = {
      firstname: newUser.firstname,
      lastname: newUser.lastname,
      email: newUser.email,
      password: newUser.password,
      role: newUser.role, // LEHRKRAFT or RAUMBETREUER
      roomIds: newUser.roomIds
    }

    try {
      const res = await fetch(`${API_URL}/auth/register`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload)
      })
      if (res.ok) {
        // Auto login after register? Or just return true
        // Implementation requirement: "Alle Nutzer ... müssen sich registrieren ... Vor der Nutzung ... anmelden"
        // So we redirect to login.
        return true
      }
    } catch (e) {
      console.error(e)
    }
    return false
  }, [])

  const logout = useCallback(() => {
    signOut({ redirect: false })
    setUser(null)
    setAuthHeader(null)
    setTickets([])
  }, [])

  const createTicket = useCallback(async (ticket: { roomId: number; title: string; description: string }) => {
    if (!authHeader) return
    try {
      const res = await fetch(`${API_URL}/tickets`, {
        method: "POST",
        headers: {
          "Authorization": authHeader,
          "Content-Type": "application/json"
        },
        body: JSON.stringify(ticket)
      })
      if (res.ok) {
        fetchTickets(authHeader) // Refresh
      }
    } catch (e) {
      console.error(e)
    }
  }, [authHeader, fetchTickets])

  const updateRooms = useCallback(async (roomIds: number[]) => {
    if (!session?.authHeader) return
    try {
      const res = await fetch(`${API_URL}/auth/profile/rooms`, {
        method: "PUT",
        headers: {
          "Authorization": session.authHeader as string,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ roomIds })
      })
      if (res.ok) {
        const updatedUser = await res.json()
        setUser(updatedUser)
        // Note: session.user won't be updated automatically until next session fetch, but local state is updated.
      }
    } catch (e) {
      console.error(e)
    }
  }, [session])

  const updateTicketStatus = useCallback(async (ticketId: number, status: TicketStatus) => {
    if (!authHeader) return
    try {
      const res = await fetch(`${API_URL}/tickets/${ticketId}/status`, {
        method: "PATCH",
        headers: {
          "Authorization": authHeader,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ status })
      })
      if (res.ok) {
        fetchTickets(authHeader) // Refresh
      }
    } catch (e) {
      console.error(e)
    }
  }, [authHeader, fetchTickets])

  return (
    <AuthContext.Provider
      value={{
        user,
        tickets,
        rooms,
        login,
        register,
        logout,
        createTicket,
        updateTicketStatus,
        updateRooms,
      }}
    >
      {children}
    </AuthContext.Provider>
  )
}

export function useAuth() {
  const context = useContext(AuthContext)
  if (!context) {
    throw new Error("useAuth must be used within an AuthProvider")
  }
  return context
}
