import { useCallback, useEffect, useMemo, useState } from 'react'
import { ArrowRight, Bot, Calendar, Clock, ExternalLink, FileText, Mail, MessageSquare, Mic, Plus, Video } from 'lucide-react'
import { extractConferenceLink } from '@/lib/calendar-event'
import { ToolConnectionsCard } from '@/components/tool-connections-card'
import { SlackIcon } from '@/components/onboarding/provider-icons'

interface TreeNode {
  path: string
  name: string
  kind: 'file' | 'dir'
  children?: TreeNode[]
  stat?: { size: number; mtimeMs: number }
}

type RunItem = { id: string; title?: string; createdAt: string }
type TaskItem = { slug: string; name: string; active: boolean; lastRunAt?: string; lastAttemptAt?: string }

type HomeViewProps = {
  tree: TreeNode[]
  runs: RunItem[]
  bgTaskSummaries: TaskItem[]
  onOpenEmail: () => void
  onOpenMeetings: () => void
  onOpenAgents: () => void
  onOpenAgent: (slug: string) => void
  onOpenNote: (path: string) => void
  onOpenRun: (runId: string) => void
  onTakeMeetingNotes: () => void
  onOpenChat?: () => void
}

type CalEvent = {
  id: string
  summary: string
  start: Date
  end: Date | null
  isAllDay: boolean
  conferenceLink: string | null
  rawStart: { dateTime?: string; date?: string } | undefined
  rawEnd: { dateTime?: string; date?: string } | undefined
  location: string | null
  htmlLink: string | null
  source: string
}

type RawCalEvent = {
  id?: string
  summary?: string
  start?: { dateTime?: string; date?: string }
  end?: { dateTime?: string; date?: string }
  location?: string
  htmlLink?: string
  status?: string
  attendees?: Array<{ self?: boolean; responseStatus?: string }>
}

type EmailThread = { threadId: string; subject: string; from: string }
type SlackFeedMessage = {
  id: string
  workspaceName?: string
  workspaceUrl?: string
  channelId?: string
  channelName?: string
  author?: string
  text: string
  ts: string
  url?: string
}

function greeting(): string {
  const h = new Date().getHours()
  if (h < 12) return 'Good morning'
  if (h < 18) return 'Good afternoon'
  return 'Good evening'
}

function todayLabel(): string {
  return new Date().toLocaleDateString([], { weekday: 'short', day: 'numeric', month: 'short' })
}

function timeOfDay(d: Date): string {
  return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
}

function relativeFromNow(start: Date): string {
  const ms = start.getTime() - Date.now()
  if (ms <= 0) return 'now'
  const min = Math.round(ms / 60000)
  if (min < 60) return `in ${min}m`
  const hr = Math.round(min / 60)
  if (hr < 24) return `in ${hr}h`
  return start.toLocaleDateString([], { weekday: 'short' })
}

function relativeAgo(iso?: string): string {
  if (!iso) return ''
  const t = new Date(iso).getTime()
  if (Number.isNaN(t)) return ''
  const min = Math.round((Date.now() - t) / 60000)
  if (min < 1) return 'just now'
  if (min < 60) return `${min}m ago`
  const hr = Math.round(min / 60)
  if (hr < 24) return `${hr}h ago`
  const d = Math.round(hr / 24)
  return `${d}d ago`
}

function relativeSlackTs(ts: string): string {
  const seconds = Number(ts.split('.')[0])
  if (!Number.isFinite(seconds)) return ''
  const iso = new Date(seconds * 1000).toISOString()
  return relativeAgo(iso)
}

// Short, non-actionable copy for the home feed — the actionable fix lives in
// Settings, so every failure routes the user there.
function homeSlackErrorCopy(kind: string | null): string {
  switch (kind) {
    case 'not_authed':
      return 'Slack needs reconnecting — open Settings → Connected accounts.'
    case 'network':
      return "Couldn't reach Slack. Check your connection."
    case 'rate_limited':
      return 'Slack is rate-limiting requests — will retry shortly.'
    default:
      return "Couldn't load Slack right now — see Settings."
  }
}

function parseAllDay(s: string): Date | null {
  const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(s)
  if (!m) return null
  return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]))
}

function normalizeCalEvent(raw: RawCalEvent, sourcePath: string): CalEvent | null {
  if (raw.status === 'cancelled') return null
  const declined = raw.attendees?.find((a) => a.self)?.responseStatus === 'declined'
  if (declined) return null
  const timed = raw.start?.dateTime
  const allDay = raw.start?.date
  const isAllDay = !timed && Boolean(allDay)
  let start: Date | null = null
  let end: Date | null = null
  if (timed) {
    start = new Date(timed)
    end = raw.end?.dateTime ? new Date(raw.end.dateTime) : null
  } else if (allDay) {
    start = parseAllDay(allDay)
    end = raw.end?.date ? parseAllDay(raw.end.date) : null
  }
  if (!start || Number.isNaN(start.getTime())) return null
  return {
    id: raw.id ?? sourcePath,
    summary: raw.summary?.trim() || '(No title)',
    start,
    end,
    isAllDay,
    conferenceLink: extractConferenceLink(raw as unknown as Record<string, unknown>) ?? null,
    rawStart: raw.start,
    rawEnd: raw.end,
    location: raw.location?.trim() || null,
    htmlLink: raw.htmlLink ?? null,
    source: sourcePath,
  }
}

function noteLabel(node: TreeNode): string {
  if (node.kind === 'file' && node.name.toLowerCase().endsWith('.md')) return node.name.slice(0, -3)
  return node.name
}

function triggerMeetingCapture(event: CalEvent, openConference: boolean) {
  window.__pendingCalendarEvent = {
    summary: event.summary,
    start: event.rawStart,
    end: event.rawEnd,
    location: event.location ?? undefined,
    htmlLink: event.htmlLink ?? undefined,
    conferenceLink: event.conferenceLink ?? undefined,
    source: event.source,
  }
  if (openConference && event.conferenceLink) {
    window.open(event.conferenceLink, '_blank')
  }
  window.dispatchEvent(new Event('calendar-block:join-meeting'))
}

const CARD = 'rounded-xl border border-border bg-card p-4'

export function HomeView({
  tree,
  runs,
  bgTaskSummaries,
  onOpenEmail,
  onOpenMeetings,
  onOpenAgents,
  onOpenAgent,
  onOpenNote,
  onOpenRun,
  onTakeMeetingNotes,
  onOpenChat,
}: HomeViewProps) {
  const [events, setEvents] = useState<CalEvent[]>([])
  const [emails, setEmails] = useState<EmailThread[]>([])
  const [slackEnabled, setSlackEnabled] = useState(false)
  const [slackMessages, setSlackMessages] = useState<SlackFeedMessage[]>([])
  const [slackError, setSlackError] = useState<string | null>(null)
  const [slackErrorKind, setSlackErrorKind] = useState<string | null>(null)

  const loadEvents = useCallback(async () => {
    try {
      const exists = await window.ipc.invoke('workspace:exists', { path: 'calendar_sync' })
      if (!exists.exists) { setEvents([]); return }
      const entries = await window.ipc.invoke('workspace:readdir', {
        path: 'calendar_sync',
        opts: { recursive: false, includeHidden: false, includeStats: false },
      })
      const jsonEntries = entries.filter((e) => e.kind === 'file' && e.name.endsWith('.json'))
      const settled = await Promise.allSettled(
        jsonEntries.map(async (entry): Promise<CalEvent | null> => {
          const result = await window.ipc.invoke('workspace:readFile', { path: entry.path, encoding: 'utf8' })
          return normalizeCalEvent(JSON.parse(result.data) as RawCalEvent, entry.path)
        }),
      )
      const out: CalEvent[] = []
      for (const r of settled) if (r.status === 'fulfilled' && r.value) out.push(r.value)
      out.sort((a, b) => a.start.getTime() - b.start.getTime())
      setEvents(out)
    } catch (err) {
      console.error('Home: failed to load events', err)
    }
  }, [])

  const loadEmails = useCallback(async () => {
    try {
      const result = await window.ipc.invoke('gmail:getImportant', { limit: 25 })
      setEmails(
        result.threads
          .filter((t) => t.unread === true)
          .slice(0, 3)
          .map((t) => ({ threadId: t.threadId, subject: t.subject ?? '(No subject)', from: t.from ?? '' })),
      )
    } catch (err) {
      console.error('Home: failed to load emails', err)
    }
  }, [])

  const loadSlackMessages = useCallback(async () => {
    try {
      const result = await window.ipc.invoke('slack:getRecentMessages', { limit: 5 })
      setSlackEnabled(result.enabled)
      setSlackMessages(result.messages)
      setSlackError(result.error ?? null)
      setSlackErrorKind(result.errorKind ?? null)
    } catch (err) {
      console.error('Home: failed to load Slack messages', err)
      setSlackEnabled(false)
      setSlackMessages([])
      setSlackError(null)
      setSlackErrorKind(null)
    }
  }, [])

  useEffect(() => { void loadEvents(); void loadEmails(); void loadSlackMessages() }, [loadEvents, loadEmails, loadSlackMessages])

  // Upcoming (not-yet-ended) events, soonest first.
  const upcoming = useMemo(() => {
    const now = Date.now()
    return events.filter((e) => {
      const end = e.end ?? (e.isAllDay ? new Date(e.start.getTime() + 864e5) : e.start)
      return end.getTime() > now
    })
  }, [events])

  const nextEvent = upcoming[0]

  const todaysEvents = useMemo(() => {
    const now = new Date()
    return upcoming.filter((e) =>
      e.start.getFullYear() === now.getFullYear() &&
      e.start.getMonth() === now.getMonth() &&
      e.start.getDate() === now.getDate(),
    )
  }, [upcoming])

  const activeAgents = useMemo(() => bgTaskSummaries.filter((t) => t.active), [bgTaskSummaries])
  const recentAgent = useMemo(() => {
    const t = (s?: string) => (s ? new Date(s).getTime() || 0 : 0)
    return [...bgTaskSummaries].sort((a, b) =>
      Math.max(t(b.lastRunAt), t(b.lastAttemptAt)) - Math.max(t(a.lastRunAt), t(a.lastAttemptAt)),
    )[0]
  }, [bgTaskSummaries])

  const recentNotes = useMemo<TreeNode[]>(() => {
    const out: TreeNode[] = []
    const walk = (nodes: TreeNode[]) => {
      for (const n of nodes) {
        if (n.path === 'knowledge/Meetings' || n.path === 'knowledge/Workspace') continue
        if (n.kind === 'file') out.push(n)
        else if (n.children?.length) walk(n.children)
      }
    }
    walk(tree)
    return out
      .filter((n) => n.stat?.mtimeMs)
      .sort((a, b) => (b.stat?.mtimeMs ?? 0) - (a.stat?.mtimeMs ?? 0))
      .slice(0, 2)
  }, [tree])

  const recentActivity = useMemo(() => {
    const items: Array<{ key: string; icon: 'note' | 'chat'; label: string; kind: string; when: number; open: () => void }> = []
    for (const n of recentNotes) {
      items.push({ key: `n:${n.path}`, icon: 'note', label: noteLabel(n), kind: 'note', when: n.stat?.mtimeMs ?? 0, open: () => onOpenNote(n.path) })
    }
    for (const r of runs.slice(0, 4)) {
      items.push({ key: `r:${r.id}`, icon: 'chat', label: r.title || '(Untitled chat)', kind: 'chat', when: new Date(r.createdAt).getTime() || 0, open: () => onOpenRun(r.id) })
    }
    return items.sort((a, b) => b.when - a.when).slice(0, 4)
  }, [recentNotes, runs, onOpenNote, onOpenRun])

  return (
    <div className="flex h-full flex-col overflow-hidden bg-muted/30">
      <div className="flex-1 overflow-y-auto px-9 py-7">
        <div className="mx-auto flex max-w-[760px] flex-col gap-[18px]">

          {/* Greeting */}
          <div className="flex items-baseline gap-3">
            <h1 className="text-[28px] font-semibold tracking-tight">{greeting()}</h1>
            <span className="text-sm text-muted-foreground">{todayLabel()}</span>
          </div>

          {/* Up-next hero */}
          {nextEvent && (
            <div className="flex items-center gap-[18px] rounded-xl bg-foreground px-5 py-[18px] text-background">
              <div className="min-w-0 flex-1">
                <div className="mb-1.5 text-[11px] font-medium uppercase tracking-wider text-background/50">
                  Up next · {nextEvent.isAllDay ? 'today' : relativeFromNow(nextEvent.start)}
                </div>
                <div className="mb-0.5 truncate text-[17px] font-semibold">{nextEvent.summary}</div>
                <div className="truncate text-[13px] text-background/70">
                  {nextEvent.isAllDay ? 'All day' : `${timeOfDay(nextEvent.start)}${nextEvent.end ? ` – ${timeOfDay(nextEvent.end)}` : ''}`}
                  {nextEvent.location ? ` · ${nextEvent.location}` : ''}
                </div>
              </div>
              <div className="flex shrink-0 gap-2">
                <button
                  type="button"
                  onClick={onTakeMeetingNotes}
                  className="rounded-md bg-background px-3.5 py-2 text-[13px] font-medium text-foreground"
                >
                  Take notes
                </button>
                {nextEvent.conferenceLink && (
                  <button
                    type="button"
                    onClick={() => window.open(nextEvent.conferenceLink!, '_blank')}
                    className="rounded-md border border-background/20 px-3 py-2 text-background"
                    aria-label="Join meeting"
                  >
                    <Video className="size-[13px]" />
                  </button>
                )}
              </div>
            </div>
          )}

          {/* Inbox + Background agents */}
          <div className="grid grid-cols-2 gap-[18px]">
            <div className={CARD}>
              <div className="mb-3 flex items-center gap-2">
                <Mail className="size-[15px]" />
                <span className="text-sm font-medium">Inbox</span>
                {emails.length > 0 && (
                  <span className="rounded-lg bg-destructive px-1.5 py-px text-[10.5px] font-semibold uppercase tracking-wide text-white">
                    {emails.length} new
                  </span>
                )}
                <span className="flex-1" />
                <button type="button" onClick={onOpenEmail} className="text-xs text-primary hover:underline">Open →</button>
              </div>
              {emails.length === 0 ? (
                <div className="py-1 text-[12.5px] text-muted-foreground">No unread important email.</div>
              ) : emails.map((e, i) => (
                <button
                  key={e.threadId}
                  type="button"
                  onClick={onOpenEmail}
                  className={`flex w-full gap-2.5 py-[7px] text-left text-[12.5px] ${i ? 'border-t border-border' : ''}`}
                >
                  <span className="w-[92px] shrink-0 truncate text-muted-foreground">{formatFrom(e.from)}</span>
                  <span className="flex-1 truncate">{e.subject}</span>
                </button>
              ))}
            </div>

            <div className={CARD}>
              <div className="mb-3 flex items-center gap-2">
                <Bot className="size-[15px]" />
                <span className="text-sm font-medium">Background agents</span>
                <span className="flex-1" />
                <span className="text-xs text-muted-foreground">{activeAgents.length} active</span>
                <button type="button" onClick={onOpenAgents} className="text-xs text-primary hover:underline">Open →</button>
              </div>
              {recentAgent ? (
                <button
                  type="button"
                  onClick={() => onOpenAgent(recentAgent.slug)}
                  className="flex w-full items-center gap-2.5 py-[7px] text-left text-[13px]"
                >
                  <span className={`size-2 shrink-0 rounded-full ${recentAgent.active ? 'bg-emerald-500' : 'bg-muted-foreground'}`} />
                  <span className="flex-1 truncate font-medium">{recentAgent.name}</span>
                  <span className="text-[11.5px] text-muted-foreground">{relativeAgo(recentAgent.lastRunAt) || '—'}</span>
                </button>
              ) : (
                <div className="py-1 text-[12.5px] text-muted-foreground">No agents yet.</div>
              )}
              <button
                type="button"
                onClick={onOpenAgents}
                className="mt-3.5 flex items-center gap-2 border-t border-border pt-3 text-[12.5px] text-primary"
              >
                <Plus className="size-3" />
                Create an agent
              </button>
            </div>
          </div>

          {/* Slack */}
          {slackEnabled && (
            <div className={CARD}>
              <div className="mb-3 flex items-center gap-2">
                <SlackIcon className="size-[15px]" />
                <span className="text-sm font-medium">Slack</span>
                <span className="flex-1" />
                <span className="text-xs text-muted-foreground">Latest messages</span>
              </div>
              {slackError ? (
                <div className="py-1 text-[12.5px] text-muted-foreground">{homeSlackErrorCopy(slackErrorKind)}</div>
              ) : slackMessages.length === 0 ? (
                <div className="py-1 text-[12.5px] text-muted-foreground">No messages worth surfacing right now.</div>
              ) : slackMessages.map((message, i) => (
                <div
                  key={message.id}
                  className={`flex items-start gap-3 py-2 text-[12.5px] ${i ? 'border-t border-border' : ''}`}
                >
                  <div className="min-w-0 flex-1">
                    <div className="mb-0.5 flex min-w-0 items-center gap-1.5 text-[11.5px] text-muted-foreground">
                      <span className="truncate">{message.channelName ?? 'Slack'}</span>
                      {message.author && (
                        <>
                          <span className="shrink-0">·</span>
                          <span className="truncate">{message.author}</span>
                        </>
                      )}
                      <span className="shrink-0">·</span>
                      <span className="shrink-0">{relativeSlackTs(message.ts)}</span>
                    </div>
                    <div className="line-clamp-2 text-foreground">{message.text}</div>
                  </div>
                  {message.url && (
                    <button
                      type="button"
                      onClick={() => window.open(message.url, '_blank')}
                      className="inline-flex shrink-0 items-center gap-1 rounded-md border border-border px-2 py-1 text-[11.5px] text-primary transition-colors hover:bg-accent"
                    >
                      Open
                      <ExternalLink className="size-3" />
                    </button>
                  )}
                </div>
              ))}
            </div>
          )}

          {/* Today's schedule */}
          <div className={CARD}>
            <div className="mb-3.5 flex items-center gap-2">
              <Calendar className="size-[14px]" />
              <span className="text-sm font-medium">Today's schedule</span>
              <span className="flex-1" />
              <button type="button" onClick={onOpenMeetings} className="text-xs text-primary hover:underline">All meetings →</button>
            </div>
            {todaysEvents.length === 0 ? (
              <div className="py-1 text-[13px] italic text-muted-foreground">No more events today.</div>
            ) : todaysEvents.map((e, i) => (
              <div key={e.id} className={`group flex items-center gap-3.5 py-2 text-[13px] ${i ? 'border-t border-border' : ''}`}>
                <span className="w-[90px] shrink-0 font-mono text-[11.5px] text-muted-foreground">
                  {e.isAllDay ? 'All day' : `${timeOfDay(e.start)}${e.end ? ` – ${timeOfDay(e.end)}` : ''}`}
                </span>
                <span className={`size-2 shrink-0 rounded-full ${i === 0 ? 'bg-emerald-500' : 'bg-border'}`} />
                <span className="min-w-0 flex-1 truncate font-medium">{e.summary}</span>
                <div className="flex shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100">
                  <button
                    type="button"
                    onClick={() => triggerMeetingCapture(e, false)}
                    className="inline-flex items-center gap-1 rounded-md border border-border px-2 py-1 text-[11.5px] text-foreground transition-colors hover:bg-accent"
                  >
                    <Mic className="size-3" />
                    Take notes
                  </button>
                  {e.conferenceLink && (
                    <button
                      type="button"
                      onClick={() => triggerMeetingCapture(e, true)}
                      className="inline-flex items-center gap-1 rounded-md border border-border px-2 py-1 text-[11.5px] text-foreground transition-colors hover:bg-accent"
                    >
                      <Video className="size-3" />
                      Join &amp; take notes
                    </button>
                  )}
                </div>
              </div>
            ))}
          </div>

          {/* Recent activity */}
          {recentActivity.length > 0 && (
            <div className={CARD}>
              <div className="mb-3 flex items-center gap-2">
                <Clock className="size-[14px]" />
                <span className="text-sm font-medium">Recent activity</span>
              </div>
              {recentActivity.map((a, i) => (
                <button
                  key={a.key}
                  type="button"
                  onClick={a.open}
                  className={`flex w-full items-center gap-3 py-2 text-left text-[13px] ${i ? 'border-t border-border' : ''}`}
                >
                  {a.icon === 'note' ? <FileText className="size-[13px] shrink-0 text-muted-foreground" /> : <MessageSquare className="size-[13px] shrink-0 text-muted-foreground" />}
                  <span className="flex-1 truncate">{a.label}</span>
                  <span className="w-[60px] text-right text-[11px] text-muted-foreground">{a.kind}</span>
                </button>
              ))}
            </div>
          )}

          {/* Tool connections */}
          <ToolConnectionsCard />

          {/* Open chat CTA */}
          {onOpenChat && (
            <button
              type="button"
              onClick={onOpenChat}
              className="flex items-center gap-3.5 rounded-xl border border-border bg-card p-4 text-left transition-colors hover:bg-accent"
            >
              <div className="min-w-0 flex-1 text-[13.5px] leading-snug">
                <span className="font-medium">Ask anything</span>
                <span className="text-muted-foreground"> — create presentations, do research, collaborate on docs.</span>
              </div>
              <span className="flex shrink-0 items-center gap-1 text-[12.5px] font-medium text-primary">
                New chat
                <ArrowRight className="size-3.5" />
              </span>
            </button>
          )}

        </div>
      </div>
    </div>
  )
}

function formatFrom(from: string): string {
  const m = /^\s*"?([^"<]+?)"?\s*<.+>\s*$/.exec(from)
  return (m ? m[1] : from).trim()
}
