import { create } from 'zustand'
import { persist } from 'zustand/middleware'

export type TaskType = 'idea' | 'task' | 'bug' | 'research' | 'plan'
export type TaskStatus = 'open' | 'todo' | 'blocked' | 'in-progress' | 'review' | 'validate' | 'archived' | 'canceled' | 'done'
export type Priority = 'low' | 'medium' | 'high' | 'urgent'
export type SprintStatus = 'planning' | 'active' | 'completed'

export interface Sprint {
  id: string
  name: string
  goal?: string
  startDate: string
  endDate: string
  status: SprintStatus
  projectId: string
  createdAt: string
}

export interface Comment {
  id: string
  text: string
  createdAt: string
  author: CommentAuthor | 'user' | 'assistant'
  replies?: Comment[]
}

export interface CommentAuthor {
  id: string
  name: string
  email?: string
  avatarUrl?: string
  type: 'human' | 'assistant'
}

export interface UserProfile {
  id: string
  name: string
  email?: string
  avatarUrl?: string
}

export interface TaskAttachment {
  id: string
  name: string
  type: string
  size: number
  dataUrl: string
  uploadedAt: string
}

export interface Task {
  id: string
  title: string
  description?: string
  type: TaskType
  status: TaskStatus
  priority: Priority
  projectId: string
  sprintId?: string
  createdAt: string
  updatedAt: string
  createdById?: string
  createdByName?: string
  createdByAvatarUrl?: string
  updatedById?: string
  updatedByName?: string
  updatedByAvatarUrl?: string
  assigneeId?: string
  assigneeName?: string
  assigneeEmail?: string
  assigneeAvatarUrl?: string
  dueDate?: string
  comments: Comment[]
  tags: string[]
  attachments?: TaskAttachment[]
}

export interface Project {
  id: string
  name: string
  description?: string
  color: string
  createdAt: string
}

interface TaskStore {
  projects: Project[]
  tasks: Task[]
  sprints: Sprint[]
  selectedProjectId: string | null
  selectedTaskId: string | null
  selectedSprintId: string | null
  currentUser: UserProfile
  isLoading: boolean
  lastSynced: number | null

  // Sync actions
  syncFromServer: () => Promise<void>
  syncToServer: () => Promise<void>
  setCurrentUser: (user: Partial<UserProfile>) => void

  // Project actions
  addProject: (name: string, description?: string) => void
  updateProject: (id: string, updates: Partial<Project>) => void
  deleteProject: (id: string) => void
  selectProject: (id: string | null) => void

  // Task actions
  addTask: (task: Omit<Task, 'id' | 'createdAt' | 'updatedAt' | 'comments'>) => void
  updateTask: (id: string, updates: Partial<Task>) => Promise<boolean>
  deleteTask: (id: string) => void
  selectTask: (id: string | null) => void

  // Sprint actions
  addSprint: (sprint: Omit<Sprint, 'id' | 'createdAt'>) => void
  updateSprint: (id: string, updates: Partial<Sprint>) => void
  deleteSprint: (id: string) => void
  selectSprint: (id: string | null) => void
  getTasksBySprint: (sprintId: string) => Task[]

  // Comment actions
  addComment: (taskId: string, text: string, author?: CommentAuthor | 'user' | 'assistant') => void
  deleteComment: (taskId: string, commentId: string) => void

  // Filters
  getTasksByProject: (projectId: string) => Task[]
  getTasksByStatus: (status: TaskStatus) => Task[]
  getTaskById: (id: string) => Task | undefined
}

// Sprint 1: Mon Feb 16 - Sun Feb 22, 2026 (current week)
const sprint1Start = new Date('2026-02-16T00:00:00.000Z')
const sprint1End = new Date('2026-02-22T23:59:59.999Z')

const defaultSprints: Sprint[] = [
  {
    id: 'sprint-1',
    name: 'Sprint 1',
    goal: 'Foundation and core features',
    startDate: sprint1Start.toISOString(),
    endDate: sprint1End.toISOString(),
    status: 'active',
    projectId: '2',
    createdAt: new Date().toISOString(),
  },
]

const defaultProjects: Project[] = [
  { id: '1', name: 'OpenClaw iOS', description: 'Main iOS app development', color: '#8b5cf6', createdAt: new Date().toISOString() },
  { id: '2', name: 'Web Projects', description: 'Web tools and dashboards', color: '#3b82f6', createdAt: new Date().toISOString() },
  { id: '3', name: 'Research', description: 'Experiments and learning', color: '#10b981', createdAt: new Date().toISOString() },
]

const defaultTasks: Task[] = [
  {
    id: '1',
    title: 'Redesign Gantt Board',
    description: 'Make it actually work with proper notes system',
    type: 'task',
    status: 'in-progress',
    priority: 'high',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c1', text: 'Need 1-to-many notes, not one big text field', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c2', text: 'Agreed - will rebuild with proper comment threads', createdAt: new Date().toISOString(), author: 'assistant' },
    ],
    tags: ['ui', 'rewrite']
  },
  {
    id: '2',
    title: 'MoodWeave App Idea',
    description: 'Social mood tracking with woven visualizations',
    type: 'idea',
    status: 'open',
    priority: 'medium',
    projectId: '1',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [],
    tags: ['ios', 'social']
  },
  {
    id: '3',
    title: 'Set up Gitea integration for code pushes',
    description: 'Create bot account on Gitea (192.168.1.128:3000) and configure git remotes for all OpenClaw projects. Decide on account name, permissions, and auth method (SSH vs token). User prefers dedicated bot account over using their personal account for audit trail.',
    type: 'task',
    status: 'done',
    priority: 'medium',
    projectId: '2',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c3', text: 'User has local Gitea at http://192.168.1.128:3000', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c4', text: 'Options: 1) Create dedicated bot account (recommended), 2) Use existing account', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c5', text: 'Account created: mbruce@topdoglabs.com / !7883Gitea (username: ai-agent)', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c6', text: 'Git configured for all 3 projects. Gitea remotes added.', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c7', text: '✅ All 3 repos created and pushed to Gitea: gantt-board, blog-backup, heartbeat-monitor', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['gitea', 'git', 'automation', 'infrastructure']
  },
  {
    id: '4',
    title: 'Redesign Heartbeat Monitor to match UptimeRobot',
    description: 'Completely redesign the Heartbeat Monitor website to be a competitor to https://uptimerobot.com. Study their design, layout, color scheme, typography, and functionality. Match their look, feel, and style as closely as possible. Include: modern dashboard, status pages, uptime charts, incident history, public status pages.',
    type: 'task',
    status: 'done',
    priority: 'high',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c8', text: 'Reference: https://uptimerobot.com - study their homepage, dashboard, and status page designs', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c9', text: 'Focus on: clean modern UI, blue/green color scheme, card-based layouts, uptime percentage displays, incident timelines', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c29', text: 'COMPLETED: Full rebuild with Next.js + shadcn/ui + Framer Motion. Dark OLED theme, glass-morphism cards, animated status indicators, sparkline visualizations, grid/list views, tooltips, progress bars. Production-grade at http://localhost:3005', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['ui', 'ux', 'redesign', 'dashboard', 'monitoring']
  },
  {
    id: '8',
    title: 'Fix Kanban board - dynamic sync without hard refresh',
    description: 'Current board uses localStorage persistence which requires hard refresh (Cmd+Shift+R) to see task updates from code changes. Need to add: server-side storage (API + database/file), or sync mechanism that checks for updates on regular refresh, or real-time updates via WebSocket/polling. User should see updates on normal page refresh without clearing cache.',
    type: 'task',
    status: 'in-progress',
    priority: 'medium',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c21', text: 'Issue: Task status changes require hard refresh to see', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c22', text: 'Current: localStorage persistence via Zustand', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c23', text: 'Need: Server-side storage or sync on regular refresh', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c44', text: 'COMPLETED: Added /api/tasks endpoint with file-based storage', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c45', text: 'COMPLETED: Store now syncs from server on load and auto-syncs changes', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c46', text: 'COMPLETED: Falls back to localStorage if server unavailable', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['ui', 'sync', 'localstorage', 'real-time']
  },
  {
    id: '5',
    title: 'Fix Blog Backup links to be clickable',
    description: 'Make links in the Daily Digest clickable in the blog backup UI. Currently links are just text that require copy-paste. Need to render markdown links properly so users can click directly. Consider different formatting for Telegram vs Blog - Telegram gets plain text summary with "Read more at [link]", Blog gets full formatted content with clickable links.',
    type: 'task',
    status: 'done',
    priority: 'medium',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c10', text: 'Blog should show: [headline](url) as clickable markdown links', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c11', text: 'Telegram gets summary + "Full digest at: http://localhost:3003"', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c41', text: 'COMPLETED: Fixed parseDigest to extract URLs from markdown links [Title](url) in title lines', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c42', text: 'COMPLETED: Title is now the clickable link with external link icon on hover', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c43', text: 'COMPLETED: Better hover states - title turns blue, external link icon appears', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['blog', 'ui', 'markdown', 'links']
  },
  {
    id: '6',
    title: 'Fix monitoring schedule - 2 of 3 sites are down',
    description: 'The cron job running every 10 minutes to check heartbeat website is failing. Currently 2 of 3 websites are down and not being auto-restarted. Debug and fix the monitoring schedule to ensure all 3 sites (gantt-board, blog-backup, heartbeat-monitor) are checked and auto-restarted properly.',
    type: 'bug',
    status: 'done',
    priority: 'urgent',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c12', text: 'Issue: Cron job exists but sites are still going down without restart', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c13', text: 'Need to verify: cron is running, checks all 3 ports, restart logic works, permissions correct', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c14', text: 'ALL SITES BACK UP - manually restarted at 14:19. Now investigating why auto-restart failed.', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c15', text: 'Problem: Port 3005 was still in use (EADDRINUSE), need better process cleanup in restart logic', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c16', text: 'FIXED: Updated cron job with pkill cleanup before restart + 2s delay. Created backup script: monitor-restart.sh', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c17', text: 'All 3 sites stable. Cron job now properly kills old processes before restarting to avoid port conflicts.', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['monitoring', 'cron', 'bug', 'infrastructure', 'urgent']
  },
  {
    id: '7',
    title: 'Investigate root cause - why are websites dying?',
    description: 'Currently monitoring only treats the symptom (restart when down). Need to investigate what is actually killing the Next.js dev servers. Check: system logs, memory usage, file watcher limits, zombie processes, macOS power management, SSH timeout, OOM killer. Set up logging to capture what happens right before crashes.',
    type: 'research',
    status: 'done',
    priority: 'high',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c18', text: 'Problem: Sites go down randomly - what is killing them?', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c19', text: 'Suspects: Memory leaks, file watcher hitting limits, SSH session timeout, macOS power nap, OOM killer', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c20', text: 'Need to add logging/capture to see what kills processes', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c27', text: 'COMPLETED: Root cause analysis done. Primary suspect: Next.js dev server memory leaks. Secondary: SSH timeout, OOM killer, power mgmt. Full report: root-cause-analysis.md. Monitoring script deployed.', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['debugging', 'research', 'infrastructure', 'root-cause']
  },
  {
    id: '9',
    title: 'Add ability to edit task priority in Kanban board',
    description: 'Currently users cannot change task priority (Low/Medium/High/Urgent) from the UI. Need to add priority editing capability to the task detail view or task card. Should be a dropdown selector allowing users to re-prioritize tasks on the fly without editing code.',
    type: 'task',
    status: 'done',
    priority: 'high',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c24', text: 'User cannot currently change priority from Medium to High in UI', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c25', text: 'Need priority dropdown/editor in task detail view', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c28', text: 'COMPLETED: Added priority buttons to task detail dialog. Click any task to see Low/Medium/High/Urgent buttons with color coding. Changes apply immediately.', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['ui', 'kanban', 'feature', 'priority']
  },
  {
    id: '10',
    title: 'RESEARCH: Find viable screenshot solution for OpenClaw on macOS',
    description: 'INVESTIGATION NEEDED: Find a reliable, persistent way for OpenClaw AI to capture screenshots of local websites running on macOS. Current browser tool requires Chrome extension which is not connected. Puppeteer workaround is temporary. Need to research and document ALL possible options including: macOS native screenshot tools (screencapture, automator), alternative browser automation tools, canvas/headless options, or any other method that works on macOS without requiring Chrome extension.',
    type: 'research',
    status: 'done',
    priority: 'high',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c29', text: 'PROBLEM: User needs to share screenshots of local websites with friends who cannot access home network. Browser tool unavailable (Chrome extension not connected).', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c30', text: 'INVESTIGATE: macOS native screenshot capabilities - screencapture CLI, Automator workflows, AppleScript', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c31', text: 'INVESTIGATE: Alternative browser automation - Playwright, Selenium, WebDriver without Chrome extension requirement', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c32', text: 'INVESTIGATE: OpenClaw Gateway configuration - browser profiles, node setup, gateway settings', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c33', text: 'INVESTIGATE: Third-party screenshot APIs or services that could work locally', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c34', text: 'DELIVERABLE: Document ALL options found with pros/cons, setup requirements, and recommendation for best solution', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c35', text: 'FINDING: /usr/sbin/screencapture exists but requires interactive mode or captures full screen - cannot target specific URL', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c36', text: 'FINDING: Google Chrome is installed at /Applications/Google Chrome.app - Playwright can use this for headless screenshots', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c37', text: 'FINDING: Playwright v1.58.2 is already available via npx - can automate Chrome without extension', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c38', text: 'FINDING: OpenClaw Gateway is running on port 18789 with browser profile "chrome" but extension not attached to any tab', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c39', text: 'SUCCESS: Playwright + Google Chrome works! Successfully captured screenshot of http://localhost:3005 using headless Chrome', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c40', text: 'RECOMMENDATION: Install Playwright globally or in workspace so screenshots work without temporary installs. Command: npm install -g playwright', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c47', text: 'COMPLETED: Playwright installed globally. Screenshots now work anytime without setup.', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['research', 'screenshot', 'macos', 'openclaw', 'investigation']
  },
  {
    id: '11',
    title: 'RESEARCH: Find iOS side projects with MRR potential',
    description: 'Research and identify iOS app ideas that have strong Monthly Recurring Revenue (MRR) opportunities. Focus on apps that are well-designed, multi-screen experiences (not single-screen utilities), and have viral potential. Look at current App Store trends, successful indie apps, and underserved niches. Consider: subscription models, freemium tiers, in-app purchases. Target ideas that leverage iOS-specific features (widgets, Live Activities, Siri, CoreML, etc.) and could generate $1K-$10K+ MRR.',
    type: 'research',
    status: 'done',
    priority: 'low',
    projectId: '3',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c48', text: 'Focus: iOS apps with MRR potential (subscriptions, recurring revenue)', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c49', text: 'Requirements: Well-thought-out, multi-screen, viral potential', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c50', text: 'Target: $1K-$10K+ MRR opportunities', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c51', text: 'Research areas: App Store trends, indie success stories, underserved niches', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c52', text: 'COMPLETED: Full research report saved to memory/ios-mrr-opportunities.md', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c53', text: 'TOP 10 IDEAS: (1) AI Translator Keyboard - $15K/mo potential, (2) Finance Widget Suite, (3) Focus Timer with Live Activities - RECOMMENDED, (4) AI Photo Enhancer, (5) Habit Tracker with Social, (6) Local Business Review Widget, (7) Audio Journal with Voice-to-Text, (8) Plant Care Tracker, (9) Sleep Sounds with HomeKit, (10) Family Password Manager', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c54', text: 'RECOMMENDATION: Focus Timer with Live Activities (#3) - Best first project. Technically achievable, proven market, high viral potential through focus streak sharing, leverages iOS 16+ features.', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['ios', 'mrr', 'research', 'side-project', 'entrepreneurship', 'app-ideas']
  },
  {
    id: '12',
    title: 'Add markdown rendering to Blog Backup',
    description: 'The blog backup page currently shows raw markdown text instead of rendered HTML. This means links appear as [text](url) instead of clickable links. Need to install a markdown renderer (like react-markdown) and update the page component to properly render markdown content as HTML with clickable links, formatted headers, lists, etc.',
    type: 'task',
    status: 'done',
    priority: 'high',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c55', text: 'Issue: Blog shows raw markdown [text](url) instead of clickable links', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c56', text: 'Solution: Install react-markdown and render content as HTML', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c57', text: 'Expected: Properly formatted markdown with clickable links, headers, lists', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c58', text: 'COMPLETED: Installed react-markdown and remark-gfm', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c59', text: 'COMPLETED: Installed @tailwindcss/typography for prose styling', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c60', text: 'COMPLETED: Updated page.tsx to render markdown as HTML with clickable links', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c61', text: 'COMPLETED: Links now open in new tab with blue styling and hover effects', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['blog', 'ui', 'markdown', 'frontend']
  },
  {
    id: '13',
    title: 'Research TTS options for Daily Digest podcast',
    description: 'Research free text-to-speech (TTS) tools to convert the daily digest blog posts into an audio podcast format. Matt wants to listen to the digest during his morning dog walks with Tully and Remy. Look into: free TTS APIs (ElevenLabs free tier, Google TTS, AWS Polly), open-source solutions (Piper, Coqui TTS), browser-based options, RSS feed generation for podcast apps, and file hosting options. The solution should be cost-effective or free since budget is a concern.',
    type: 'research',
    status: 'open',
    priority: 'medium',
    projectId: '2',
    sprintId: 'sprint-1',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    comments: [
      { id: 'c62', text: 'Goal: Convert daily digest text to audio for dog walks', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c63', text: 'Requirement: Free or very low cost solution', createdAt: new Date().toISOString(), author: 'user' },
      { id: 'c64', text: 'Look into: ElevenLabs free tier, Google TTS, AWS Polly, Piper, Coqui TTS', createdAt: new Date().toISOString(), author: 'assistant' },
      { id: 'c65', text: 'Also research: RSS feed generation, podcast hosting options', createdAt: new Date().toISOString(), author: 'assistant' }
    ],
    tags: ['research', 'tts', 'podcast', 'audio', 'digest', 'accessibility']
  }
]

const createLocalUserProfile = (): UserProfile => ({
  id: `user-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
  name: 'Local User',
})

const defaultCurrentUser = createLocalUserProfile()

const normalizeUserProfile = (value: unknown, fallback: UserProfile = defaultCurrentUser): UserProfile => {
  if (!value || typeof value !== 'object') return fallback
  const candidate = value as Partial<UserProfile>
  const id = typeof candidate.id === 'string' && candidate.id.trim().length > 0 ? candidate.id : fallback.id
  const name = typeof candidate.name === 'string' && candidate.name.trim().length > 0 ? candidate.name.trim() : fallback.name
  const email = typeof candidate.email === 'string' && candidate.email.trim().length > 0 ? candidate.email.trim() : undefined
  const avatarUrl = typeof candidate.avatarUrl === 'string' && candidate.avatarUrl.trim().length > 0 ? candidate.avatarUrl : undefined
  return { id, name, email, avatarUrl }
}

const profileToCommentAuthor = (profile: UserProfile): CommentAuthor => ({
  id: profile.id,
  name: profile.name,
  email: profile.email,
  avatarUrl: profile.avatarUrl,
  type: 'human',
})

const assistantAuthor: CommentAuthor = {
  id: 'assistant',
  name: 'Assistant',
  type: 'assistant',
}

const normalizeCommentAuthor = (value: unknown): CommentAuthor => {
  if (value === 'assistant') return assistantAuthor
  if (value === 'user') {
    return {
      id: 'legacy-user',
      name: 'User',
      type: 'human',
    }
  }

  if (!value || typeof value !== 'object') {
    return {
      id: 'legacy-user',
      name: 'User',
      type: 'human',
    }
  }

  const candidate = value as Partial<CommentAuthor>
  const type: CommentAuthor['type'] =
    candidate.type === 'assistant' || candidate.id === 'assistant' ? 'assistant' : 'human'

  const id = typeof candidate.id === 'string' && candidate.id.trim().length > 0
    ? candidate.id
    : type === 'assistant'
      ? 'assistant'
      : 'legacy-user'
  const name = typeof candidate.name === 'string' && candidate.name.trim().length > 0
    ? candidate.name.trim()
    : type === 'assistant'
      ? 'Assistant'
      : 'User'
  const email = typeof candidate.email === 'string' && candidate.email.trim().length > 0 ? candidate.email.trim() : undefined
  const avatarUrl = typeof candidate.avatarUrl === 'string' && candidate.avatarUrl.trim().length > 0 ? candidate.avatarUrl : undefined

  return { id, name, email, avatarUrl, type }
}

const normalizeComments = (value: unknown): Comment[] => {
  if (!Array.isArray(value)) return []

  const comments: Comment[] = []
  
  for (const entry of value) {
    if (!entry || typeof entry !== 'object') continue
    const candidate = entry as Partial<Comment>
    if (typeof candidate.id !== 'string' || typeof candidate.text !== 'string') continue

    comments.push({
      id: candidate.id,
      text: candidate.text,
      createdAt: typeof candidate.createdAt === 'string' ? candidate.createdAt : new Date().toISOString(),
      author: normalizeCommentAuthor(candidate.author),
      replies: normalizeComments(candidate.replies),
    })
  }
  
  return comments
}

const normalizeAttachments = (value: unknown): TaskAttachment[] => {
  if (!Array.isArray(value)) return []

  return value
    .map((entry) => {
      if (!entry || typeof entry !== 'object') return null
      const candidate = entry as Partial<TaskAttachment>
      if (typeof candidate.id !== 'string' || typeof candidate.name !== 'string' || typeof candidate.dataUrl !== 'string') {
        return null
      }

      return {
        id: candidate.id,
        name: candidate.name,
        type: typeof candidate.type === 'string' ? candidate.type : 'application/octet-stream',
        size: typeof candidate.size === 'number' ? candidate.size : 0,
        dataUrl: candidate.dataUrl,
        uploadedAt: typeof candidate.uploadedAt === 'string' ? candidate.uploadedAt : new Date().toISOString(),
      }
    })
    .filter((attachment): attachment is TaskAttachment => attachment !== null)
}

const normalizeTask = (task: Task): Task => ({
  ...task,
  comments: normalizeComments(task.comments),
  tags: Array.isArray(task.tags) ? task.tags.filter((tag): tag is string => typeof tag === 'string' && tag.trim().length > 0) : [],
  attachments: normalizeAttachments(task.attachments),
  createdById: typeof task.createdById === 'string' && task.createdById.trim().length > 0 ? task.createdById : undefined,
  createdByName: typeof task.createdByName === 'string' && task.createdByName.trim().length > 0 ? task.createdByName : undefined,
  createdByAvatarUrl: typeof task.createdByAvatarUrl === 'string' && task.createdByAvatarUrl.trim().length > 0 ? task.createdByAvatarUrl : undefined,
  updatedById: typeof task.updatedById === 'string' && task.updatedById.trim().length > 0 ? task.updatedById : undefined,
  updatedByName: typeof task.updatedByName === 'string' && task.updatedByName.trim().length > 0 ? task.updatedByName : undefined,
  updatedByAvatarUrl: typeof task.updatedByAvatarUrl === 'string' && task.updatedByAvatarUrl.trim().length > 0 ? task.updatedByAvatarUrl : undefined,
  assigneeId: typeof task.assigneeId === 'string' && task.assigneeId.trim().length > 0 ? task.assigneeId : undefined,
  assigneeName: typeof task.assigneeName === 'string' && task.assigneeName.trim().length > 0 ? task.assigneeName : undefined,
  assigneeEmail: typeof task.assigneeEmail === 'string' && task.assigneeEmail.trim().length > 0 ? task.assigneeEmail : undefined,
  assigneeAvatarUrl: typeof task.assigneeAvatarUrl === 'string' && task.assigneeAvatarUrl.trim().length > 0 ? task.assigneeAvatarUrl : undefined,
})

const removeCommentFromThread = (comments: Comment[], targetId: string): Comment[] =>
  comments
    .filter((comment) => comment.id !== targetId)
    .map((comment) => ({
      ...comment,
      replies: removeCommentFromThread(normalizeComments(comment.replies), targetId),
    }))

const generateTaskId = (): string => {
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
    return crypto.randomUUID()
  }
  return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
}

// Helper to sync a single task to server (lightweight)
async function syncTaskToServer(task: Task) {
  console.log('>>> syncTaskToServer: saving task', task.id, task.title)
  try {
    const res = await fetch('/api/tasks', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ task }),
    })
    if (res.ok) {
      console.log('>>> syncTaskToServer: saved successfully')
      return true
    } else {
      const errorPayload = await res.json().catch(() => null)
      console.error('>>> syncTaskToServer: failed with status', res.status, errorPayload)
      return false
    }
  } catch (error) {
    console.error('>>> syncTaskToServer: Failed to sync:', error)
    return false
  }
}

// Helper to delete a task from server
async function deleteTaskFromServer(taskId: string) {
  console.log('>>> deleteTaskFromServer: deleting task', taskId)
  try {
    const res = await fetch('/api/tasks', {
      method: 'DELETE',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ id: taskId }),
    })
    if (res.ok) {
      console.log('>>> deleteTaskFromServer: deleted successfully')
      return true
    } else {
      console.error('>>> deleteTaskFromServer: failed with status', res.status)
      return false
    }
  } catch (error) {
    console.error('>>> deleteTaskFromServer: Failed to delete:', error)
    return false
  }
}

// Legacy bulk sync (for projects/sprints only)
async function syncToServer(projects: Project[], tasks: Task[], sprints: Sprint[]) {
  console.log('>>> syncToServer: legacy bulk sync - projects/sprints only')
  // Only sync projects and sprints in bulk, tasks are handled individually
  try {
    const res = await fetch('/api/projects', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ projects, sprints }),
    })
    if (res.ok) {
      console.log('>>> syncToServer: saved projects/sprints successfully')
    } else {
      console.error('>>> syncToServer: failed with status', res.status)
    }
  } catch (error) {
    console.error('>>> syncToServer: Failed to sync:', error)
  }
}

export const useTaskStore = create<TaskStore>()(
  persist(
    (set, get) => ({
      projects: defaultProjects,
      tasks: defaultTasks,
      sprints: defaultSprints,
      selectedProjectId: '1',
      selectedTaskId: null,
      selectedSprintId: null,
      currentUser: defaultCurrentUser,
      isLoading: false,
      lastSynced: null,

      syncFromServer: async () => {
        console.log('>>> syncFromServer START')
        set({ isLoading: true })
        try {
          const res = await fetch('/api/tasks')
          console.log('>>> syncFromServer: API response status:', res.status)
          if (res.ok) {
            const data = await res.json()
            console.log('>>> syncFromServer: fetched data:', {
              projectsCount: data.projects?.length,
              tasksCount: data.tasks?.length,
              sprintsCount: data.sprints?.length,
              firstTaskTitle: data.tasks?.[0]?.title,
              lastUpdated: data.lastUpdated,
            })
            console.log('>>> syncFromServer: current store tasks count BEFORE set:', get().tasks.length)
            // ALWAYS use server data if API returns successfully
            set({
              projects: data.projects || [],
              tasks: (data.tasks || []).map((task: Task) => normalizeTask(task)),
              sprints: data.sprints || [],
              lastSynced: Date.now(),
            })
            console.log('>>> syncFromServer: store tasks count AFTER set:', get().tasks.length)
          } else {
            console.error('>>> syncFromServer: API returned error status:', res.status)
          }
        } catch (error) {
          console.error('>>> syncFromServer: Failed to sync from server:', error)
          // Keep local data if server fails
        } finally {
          set({ isLoading: false })
          console.log('>>> syncFromServer END')
        }
      },

      syncToServer: async () => {
        const { projects, tasks, sprints } = get()
        await syncToServer(projects, tasks, sprints)
        set({ lastSynced: Date.now() })
      },

      setCurrentUser: (user) => {
        set((state) => ({ currentUser: normalizeUserProfile(user, state.currentUser) }))
      },

      addProject: (name, description) => {
        const colors = ['#8b5cf6', '#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#ec4899', '#06b6d4']
        const newProject: Project = {
          id: Date.now().toString(),
          name,
          description,
          color: colors[Math.floor(Math.random() * colors.length)],
          createdAt: new Date().toISOString(),
        }
        set((state) => {
          const newState = { projects: [...state.projects, newProject] }
          // Sync to server
          syncToServer(newState.projects, state.tasks, state.sprints)
          return newState
        })
      },

      updateProject: (id, updates) => {
        set((state) => {
          const newProjects = state.projects.map((p) => (p.id === id ? { ...p, ...updates } : p))
          syncToServer(newProjects, state.tasks, state.sprints)
          return { projects: newProjects }
        })
      },

      deleteProject: (id) => {
        set((state) => {
          const newProjects = state.projects.filter((p) => p.id !== id)
          const newTasks = state.tasks.filter((t) => t.projectId !== id)
          const newSprints = state.sprints.filter((s) => s.projectId !== id)
          syncToServer(newProjects, newTasks, newSprints)
          return {
            projects: newProjects,
            tasks: newTasks,
            sprints: newSprints,
            selectedProjectId: state.selectedProjectId === id ? null : state.selectedProjectId,
          }
        })
      },

      selectProject: (id) => set({ selectedProjectId: id, selectedTaskId: null, selectedSprintId: null }),

      addTask: (task) => {
        const actor = profileToCommentAuthor(get().currentUser)
        const newTask: Task = {
          ...task,
          id: generateTaskId(),
          createdAt: new Date().toISOString(),
          updatedAt: new Date().toISOString(),
          createdById: actor.id,
          createdByName: actor.name,
          createdByAvatarUrl: actor.avatarUrl,
          updatedById: actor.id,
          updatedByName: actor.name,
          updatedByAvatarUrl: actor.avatarUrl,
          assigneeId: task.assigneeId || actor.id,
          assigneeName: task.assigneeName || actor.name,
          assigneeEmail: task.assigneeEmail || actor.email,
          assigneeAvatarUrl: task.assigneeAvatarUrl || actor.avatarUrl,
          comments: normalizeComments([]),
          attachments: normalizeAttachments(task.attachments),
        }
        set((state) => {
          const newTasks = [...state.tasks, newTask]
          // Sync individual task to server (lightweight)
          syncTaskToServer(newTask)
          return { tasks: newTasks }
        })
      },

      updateTask: async (id, updates) => {
        console.log('updateTask called:', id, updates)
        let syncSuccess = false
        let updatedTask: Task | undefined

        set((state) => {
          const actor = profileToCommentAuthor(state.currentUser)
          const newTasks = state.tasks.map((t) =>
            t.id === id
              ? normalizeTask({
                  ...t,
                  ...updates,
                  comments: updates.comments !== undefined ? normalizeComments(updates.comments) : t.comments,
                  attachments: updates.attachments !== undefined ? normalizeAttachments(updates.attachments) : t.attachments,
                  updatedAt: new Date().toISOString(),
                  updatedById: actor.id,
                  updatedByName: actor.name,
                  updatedByAvatarUrl: actor.avatarUrl,
                } as Task)
              : t
          )
          updatedTask = newTasks.find(t => t.id === id)
          console.log('updateTask: updated task:', updatedTask)
          return { tasks: newTasks }
        })

        // Sync individual task to server (lightweight)
        if (updatedTask) {
          syncSuccess = await syncTaskToServer(updatedTask)
        }

        return syncSuccess
      },

      deleteTask: (id) => {
        set((state) => {
          const newTasks = state.tasks.filter((t) => t.id !== id)
          // Delete individual task from server (lightweight)
          deleteTaskFromServer(id)
          return {
            tasks: newTasks,
            selectedTaskId: state.selectedTaskId === id ? null : state.selectedTaskId,
          }
        })
      },

      selectTask: (id) => set({ selectedTaskId: id }),

      // Sprint actions
      addSprint: (sprint) => {
        const newSprint: Sprint = {
          ...sprint,
          id: Date.now().toString(),
          createdAt: new Date().toISOString(),
        }
        set((state) => {
          const newSprints = [...state.sprints, newSprint]
          syncToServer(state.projects, state.tasks, newSprints)
          return { sprints: newSprints }
        })
      },

      updateSprint: (id, updates) => {
        set((state) => {
          const newSprints = state.sprints.map((s) =>
            s.id === id ? { ...s, ...updates } : s
          )
          syncToServer(state.projects, state.tasks, newSprints)
          return { sprints: newSprints }
        })
      },

      deleteSprint: (id) => {
        set((state) => {
          const newSprints = state.sprints.filter((s) => s.id !== id)
          const newTasks = state.tasks.map((t) =>
            t.sprintId === id ? { ...t, sprintId: undefined } : t
          )
          syncToServer(state.projects, newTasks, newSprints)
          return {
            sprints: newSprints,
            tasks: newTasks,
            selectedSprintId: state.selectedSprintId === id ? null : state.selectedSprintId,
          }
        })
      },

      selectSprint: (id) => set({ selectedSprintId: id }),

      getTasksBySprint: (sprintId) => {
        return get().tasks.filter((t) => t.sprintId === sprintId)
      },

      addComment: (taskId, text, author) => {
        const actor = normalizeCommentAuthor(author ?? profileToCommentAuthor(get().currentUser))
        const newComment: Comment = {
          id: Date.now().toString(),
          text,
          createdAt: new Date().toISOString(),
          author: actor,
          replies: [],
        }
        set((state) => {
          const updater = profileToCommentAuthor(state.currentUser)
          const newTasks = state.tasks.map((t) =>
            t.id === taskId
              ? {
                  ...t,
                  comments: [...normalizeComments(t.comments), newComment],
                  updatedAt: new Date().toISOString(),
                  updatedById: updater.id,
                  updatedByName: updater.name,
                  updatedByAvatarUrl: updater.avatarUrl,
                }
              : t
          )
          const updatedTask = newTasks.find(t => t.id === taskId)
          if (updatedTask) {
            syncTaskToServer(updatedTask)
          }
          return { tasks: newTasks }
        })
      },

      deleteComment: (taskId, commentId) => {
        set((state) => {
          const updater = profileToCommentAuthor(state.currentUser)
          const newTasks = state.tasks.map((t) =>
            t.id === taskId
              ? {
                  ...t,
                  comments: removeCommentFromThread(normalizeComments(t.comments), commentId),
                  updatedAt: new Date().toISOString(),
                  updatedById: updater.id,
                  updatedByName: updater.name,
                  updatedByAvatarUrl: updater.avatarUrl,
                }
              : t
          )
          const updatedTask = newTasks.find(t => t.id === taskId)
          if (updatedTask) {
            syncTaskToServer(updatedTask)
          }
          return { tasks: newTasks }
        })
      },

      getTasksByProject: (projectId) => {
        return get().tasks.filter((t) => t.projectId === projectId)
      },

      getTasksByStatus: (status) => {
        return get().tasks.filter((t) => t.status === status)
      },

      getTaskById: (id) => {
        return get().tasks.find((t) => t.id === id)
      },
    }),
    {
      name: 'task-store',
      partialize: (state) => ({
        // Persist user identity and UI state, not task data
        currentUser: state.currentUser,
        selectedProjectId: state.selectedProjectId,
        selectedTaskId: state.selectedTaskId,
        selectedSprintId: state.selectedSprintId,
      }),
      onRehydrateStorage: () => {
        console.log('>>> PERSIST: onRehydrateStorage called')
        return (state, error) => {
          if (error) {
            console.log('>>> PERSIST: Rehydration error:', error)
          } else {
            console.log('>>> PERSIST: Rehydrated state:', {
              currentUser: state?.currentUser?.name,
              selectedProjectId: state?.selectedProjectId,
              selectedTaskId: state?.selectedTaskId,
              tasksCount: state?.tasks?.length,
            })
          }
        }
      },
    }
  )
)
