'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import { createClient } from '@/lib/supabase/client'

const PAGE_SIZE = 20

type AuditEntry = {
  id: string
  project_id: string
  user_id: string
  action_type: string
  entity_id: string
  previous_state: Record<string, unknown> | null
  new_state: Record<string, unknown> | null
  created_at: string
  user_display_name?: string
}

type ActivityHistorySidebarProps = {
  projectId: string
  onClose: () => void
  onSelectEntity: (entityId: string, actionType: string) => void
}

const ACTION_LABELS: Record<string, string> = {
  node_add: 'Added node',
  node_update: 'Updated node',
  node_delete: 'Deleted node',
  edge_add: 'Added edge',
  edge_update: 'Updated edge',
  edge_delete: 'Deleted edge',
}

const ACTION_ICONS: Record<string, string> = {
  node_add: '+',
  node_update: '~',
  node_delete: '-',
  edge_add: '+',
  edge_update: '~',
  edge_delete: '-',
}

const ACTION_COLORS: Record<string, string> = {
  node_add: 'text-green-500',
  node_update: 'text-blue-500',
  node_delete: 'text-red-500',
  edge_add: 'text-green-500',
  edge_update: 'text-blue-500',
  edge_delete: 'text-red-500',
}

// Same hash logic as PresenceAvatars and FlowchartEditor
const PRESENCE_COLORS = [
  '#EF4444', '#F97316', '#F59E0B', '#10B981',
  '#3B82F6', '#8B5CF6', '#EC4899', '#14B8A6',
  '#6366F1', '#F43F5E', '#84CC16', '#06B6D4',
]

function getUserColor(userId: string): string {
  let hash = 0
  for (let i = 0; i < userId.length; i++) {
    hash = ((hash << 5) - hash + userId.charCodeAt(i)) | 0
  }
  return PRESENCE_COLORS[Math.abs(hash) % PRESENCE_COLORS.length]
}

function getEntityDescription(entry: AuditEntry): string {
  const state = entry.new_state || entry.previous_state
  if (!state) return entry.entity_id.slice(0, 8)

  if (entry.action_type.startsWith('node_')) {
    const type = (state as Record<string, unknown>).type as string | undefined
    const data = (state as Record<string, unknown>).data as Record<string, unknown> | undefined
    if (type === 'dialogue' && data) {
      const speaker = (data.speaker as string) || (data.characterId as string) || ''
      return speaker ? `Dialogue (${speaker})` : 'Dialogue node'
    }
    if (type === 'choice' && data) {
      const question = (data.question as string) || ''
      return question ? `Choice: "${question.slice(0, 20)}${question.length > 20 ? '…' : ''}"` : 'Choice node'
    }
    if (type === 'variable' && data) {
      const name = (data.variableName as string) || ''
      return name ? `Variable: ${name}` : 'Variable node'
    }
    return `${type || 'Unknown'} node`
  }

  // Edge entries
  return 'Connection'
}

function formatTime(dateStr: string): string {
  const date = new Date(dateStr)
  return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
}

function getTimePeriod(dateStr: string): 'Today' | 'Yesterday' | 'Earlier' {
  const date = new Date(dateStr)
  const now = new Date()
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
  const yesterday = new Date(today)
  yesterday.setDate(yesterday.getDate() - 1)

  if (date >= today) return 'Today'
  if (date >= yesterday) return 'Yesterday'
  return 'Earlier'
}

type GroupedEntries = {
  period: 'Today' | 'Yesterday' | 'Earlier'
  entries: AuditEntry[]
}

function groupByPeriod(entries: AuditEntry[]): GroupedEntries[] {
  const groups: Record<string, AuditEntry[]> = {}
  const order: ('Today' | 'Yesterday' | 'Earlier')[] = ['Today', 'Yesterday', 'Earlier']

  for (const entry of entries) {
    const period = getTimePeriod(entry.created_at)
    if (!groups[period]) groups[period] = []
    groups[period].push(entry)
  }

  return order
    .filter((p) => groups[p] && groups[p].length > 0)
    .map((p) => ({ period: p, entries: groups[p] }))
}

export default function ActivityHistorySidebar({
  projectId,
  onClose,
  onSelectEntity,
}: ActivityHistorySidebarProps) {
  const [entries, setEntries] = useState<AuditEntry[]>([])
  const [loading, setLoading] = useState(true)
  const [loadingMore, setLoadingMore] = useState(false)
  const [hasMore, setHasMore] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const mountedRef = useRef(true)

  const fetchEntriesRaw = useCallback(async (offset: number): Promise<{ entries: AuditEntry[]; hasMore: boolean; error?: string }> => {
    const supabase = createClient()
    const { data, error: fetchError } = await supabase
      .from('audit_trail')
      .select('id, project_id, user_id, action_type, entity_id, previous_state, new_state, created_at')
      .eq('project_id', projectId)
      .order('created_at', { ascending: false })
      .range(offset, offset + PAGE_SIZE - 1)

    if (fetchError) {
      return { entries: [], hasMore: false, error: fetchError.message }
    }

    const moreAvailable = !!data && data.length >= PAGE_SIZE

    // Fetch user display names for the entries
    if (data && data.length > 0) {
      const userIds = [...new Set(data.map((e) => e.user_id))]
      const { data: profiles } = await supabase
        .from('profiles')
        .select('id, display_name')
        .in('id', userIds)

      const nameMap = new Map<string, string>()
      if (profiles) {
        for (const p of profiles) {
          nameMap.set(p.id, p.display_name || 'Unknown')
        }
      }

      return {
        entries: data.map((e) => ({
          ...e,
          user_display_name: nameMap.get(e.user_id) || 'Unknown',
        })),
        hasMore: moreAvailable,
      }
    }

    return { entries: data || [], hasMore: moreAvailable }
  }, [projectId])

  useEffect(() => {
    mountedRef.current = true
    const controller = new AbortController()
    fetchEntriesRaw(0).then((result) => {
      if (!controller.signal.aborted && mountedRef.current) {
        if (result.error) {
          setError(result.error)
        } else {
          setEntries(result.entries)
          setHasMore(result.hasMore)
        }
        setLoading(false)
      }
    })
    return () => {
      controller.abort()
      mountedRef.current = false
    }
  }, [fetchEntriesRaw])

  const handleLoadMore = async () => {
    setLoadingMore(true)
    const result = await fetchEntriesRaw(entries.length)
    if (result.error) {
      setError(result.error)
    } else {
      setEntries((prev) => [...prev, ...result.entries])
      setHasMore(result.hasMore)
    }
    setLoadingMore(false)
  }

  const grouped = groupByPeriod(entries)

  return (
    <div className="absolute right-0 top-0 z-40 flex h-full w-80 flex-col border-l border-zinc-200 bg-white shadow-lg dark:border-zinc-700 dark:bg-zinc-800">
      <div className="flex items-center justify-between border-b border-zinc-200 px-4 py-3 dark:border-zinc-700">
        <h2 className="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
          Activity History
        </h2>
        <button
          onClick={onClose}
          className="rounded p-1 text-zinc-400 hover:bg-zinc-100 hover:text-zinc-600 dark:hover:bg-zinc-700 dark:hover:text-zinc-300"
          title="Close"
        >
          <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
            <path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
          </svg>
        </button>
      </div>

      <div className="flex-1 overflow-y-auto">
        {loading && (
          <div className="flex items-center justify-center py-8">
            <svg className="h-5 w-5 animate-spin text-zinc-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
              <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
              <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
            </svg>
          </div>
        )}

        {error && (
          <div className="px-4 py-3 text-sm text-red-500 dark:text-red-400">
            Failed to load history: {error}
          </div>
        )}

        {!loading && !error && entries.length === 0 && (
          <div className="px-4 py-8 text-center text-sm text-zinc-400 dark:text-zinc-500">
            No activity recorded yet
          </div>
        )}

        {!loading && grouped.map((group) => (
          <div key={group.period}>
            <div className="sticky top-0 bg-zinc-50 px-4 py-1.5 text-xs font-medium uppercase tracking-wide text-zinc-500 dark:bg-zinc-850 dark:text-zinc-400" style={{ backgroundColor: 'inherit' }}>
              <div className="bg-zinc-50 dark:bg-zinc-800">
                {group.period}
              </div>
            </div>
            <div className="divide-y divide-zinc-100 dark:divide-zinc-700/50">
              {group.entries.map((entry) => {
                const userColor = getUserColor(entry.user_id)
                const isDeleted = entry.action_type.endsWith('_delete')
                return (
                  <button
                    key={entry.id}
                    onClick={() => !isDeleted && onSelectEntity(entry.entity_id, entry.action_type)}
                    disabled={isDeleted}
                    className={`w-full px-4 py-2.5 text-left transition-colors ${
                      isDeleted
                        ? 'cursor-default opacity-60'
                        : 'hover:bg-zinc-50 dark:hover:bg-zinc-700/50'
                    }`}
                  >
                    <div className="flex items-start gap-2.5">
                      <div
                        className="mt-1 h-2 w-2 flex-shrink-0 rounded-full"
                        style={{ backgroundColor: userColor }}
                        title={entry.user_display_name}
                      />
                      <div className="min-w-0 flex-1">
                        <div className="flex items-center gap-1.5">
                          <span className={`text-xs font-bold ${ACTION_COLORS[entry.action_type] || 'text-zinc-500'}`}>
                            {ACTION_ICONS[entry.action_type] || '?'}
                          </span>
                          <span className="truncate text-xs font-medium text-zinc-800 dark:text-zinc-200">
                            {ACTION_LABELS[entry.action_type] || entry.action_type}
                          </span>
                        </div>
                        <div className="mt-0.5 truncate text-xs text-zinc-500 dark:text-zinc-400">
                          {getEntityDescription(entry)}
                        </div>
                        <div className="mt-0.5 flex items-center gap-1.5 text-[10px] text-zinc-400 dark:text-zinc-500">
                          <span>{entry.user_display_name}</span>
                          <span>·</span>
                          <span>{formatTime(entry.created_at)}</span>
                        </div>
                      </div>
                    </div>
                  </button>
                )
              })}
            </div>
          </div>
        ))}

        {!loading && hasMore && entries.length > 0 && (
          <div className="px-4 py-3">
            <button
              onClick={handleLoadMore}
              disabled={loadingMore}
              className="w-full rounded border border-zinc-300 bg-white px-3 py-1.5 text-xs font-medium text-zinc-600 hover:bg-zinc-50 disabled:opacity-50 dark:border-zinc-600 dark:bg-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-600"
            >
              {loadingMore ? 'Loading...' : 'Load more'}
            </button>
          </div>
        )}
      </div>
    </div>
  )
}
