import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, waitFor, fireEvent, act } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { MemoryRouter } from 'react-router-dom'
import Home from '../pages/Home'
import { useAuthStore } from '../store/auth'

vi.mock('../store/auth', () => ({
  useAuthStore: vi.fn(),
}))

vi.mock('../api/habits', () => ({
  habitsApi: {
    list: vi.fn(),
    getLogs: vi.fn(),
    log: vi.fn(),
    getStats: vi.fn(),
    getHabitStats: vi.fn(),
    getFreezes: vi.fn(),
    deleteLog: vi.fn(),
  },
}))

vi.mock('../api/tasks', () => ({
  tasksApi: {
    today: vi.fn(),
    complete: vi.fn(),
    uncomplete: vi.fn(),
  },
}))

vi.mock('../components/Navigation', () => ({
  default: () => <nav data-testid="navigation">Nav</nav>,
}))

vi.mock('../components/CreateTaskModal', () => ({
  default: ({ open, onClose }) => open ? <div data-testid="create-task-modal"><button onClick={onClose}>Close</button></div> : null,
}))

vi.mock('../components/LogHabitModal', () => ({
  default: ({ open, onClose, habit, onLogDate }) => open ? (
    <div data-testid="log-habit-modal">
      <span>{habit?.name}</span>
      <button onClick={onClose}>Close</button>
      <button onClick={() => onLogDate && onLogDate(habit?.id, '2026-03-01')}>Log Date</button>
    </div>
  ) : null,
}))

import { habitsApi } from '../api/habits'
import { tasksApi } from '../api/tasks'

const mockUser = { id: 1, username: 'testuser', email: 'test@test.com' }
const mockLogout = vi.fn()

const mockHabits = [
  { id: 1, name: 'Exercise', frequency: 'daily', color: '#6366f1', icon: '💪', is_archived: false, created_at: '2026-01-01T00:00:00Z' },
  { id: 2, name: 'Read', frequency: 'weekly', target_days: [1,2,3,4,5,6,7], color: '#22c55e', icon: '📚', is_archived: false, created_at: '2026-01-01T00:00:00Z' },
]

const mockTasks = [
  { id: 1, title: 'Buy groceries', completed: false, priority: 1, due_date: null, icon: '📋', color: '#6366f1', is_recurring: false, recurrence_type: null },
  { id: 2, title: 'Completed task', completed: true, priority: 0, due_date: null, icon: '✅', color: '#22c55e', is_recurring: false, recurrence_type: null },
]

const renderHome = () => {
  const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } })
  return render(
    <QueryClientProvider client={qc}>
      <MemoryRouter>
        <Home />
      </MemoryRouter>
    </QueryClientProvider>
  )
}

describe('Home page', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    useAuthStore.mockReturnValue({ user: mockUser, logout: mockLogout })
    habitsApi.list.mockResolvedValue([])
    habitsApi.getLogs.mockResolvedValue([])
    habitsApi.getStats.mockResolvedValue({ total_habits: 0, completion_rate: 0, today_completed: 3, active_habits: 5 })
    habitsApi.getFreezes.mockResolvedValue([])
    habitsApi.deleteLog.mockResolvedValue({})
    tasksApi.today.mockResolvedValue([])
  })

  it('renders home page', async () => {
    renderHome()
    await waitFor(() => {
      expect(screen.getByText(/Привет|Главная/)).toBeInTheDocument()
    })
  })

  it('renders navigation', () => {
    renderHome()
    expect(screen.getByTestId('navigation')).toBeInTheDocument()
  })

  it('shows user greeting', async () => {
    renderHome()
    await waitFor(() => {
      expect(screen.getByText(/testuser/i)).toBeInTheDocument()
    })
  })

  it('calls logout when logout button clicked', async () => {
    renderHome()
    await waitFor(() => {
      expect(screen.getByText(/testuser/i)).toBeInTheDocument()
    })
    const logoutBtn = document.querySelector('[title="Выйти"]')
    if (logoutBtn) {
      fireEvent.click(logoutBtn)
      expect(mockLogout).toHaveBeenCalled()
    }
  })

  it('shows progress section', async () => {
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Прогресс на сегодня')).toBeInTheDocument()
    })
  })

  it('shows stats when available', async () => {
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Выполнено')).toBeInTheDocument()
      expect(screen.getByText('Активных')).toBeInTheDocument()
    })
  })

  it('shows empty tasks state', async () => {
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Нет задач на сегодня')).toBeInTheDocument()
    })
  })

  it('renders tasks when present', async () => {
    tasksApi.today.mockResolvedValue(mockTasks)
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Buy groceries')).toBeInTheDocument()
    })
  })

  it('renders only active tasks in main list', async () => {
    tasksApi.today.mockResolvedValue(mockTasks)
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Buy groceries')).toBeInTheDocument()
    })
  })

  it('shows free day message when no habits for today', async () => {
    habitsApi.list.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Свободный день!')).toBeInTheDocument()
    })
  })

  it('renders habits section', async () => {
    habitsApi.list.mockResolvedValue(mockHabits)
    habitsApi.getLogs.mockResolvedValue([])
    habitsApi.getFreezes.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Привычки')).toBeInTheDocument()
    })
  })

  it('opens create task modal when plus button clicked', async () => {
    tasksApi.today.mockResolvedValue(mockTasks)
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Задачи на сегодня')).toBeInTheDocument()
    })
    const plusBtns = document.querySelectorAll('button')
    const plusBtn = Array.from(plusBtns).find(b => b.querySelector('svg'))
    // Click the + button in tasks header
    const taskHeader = screen.getByText('Задачи на сегодня')
    const headerDiv = taskHeader.closest('div')
    const btnsInHeader = headerDiv?.querySelectorAll('button')
    if (btnsInHeader && btnsInHeader.length > 0) {
      fireEvent.click(btnsInHeader[0])
      await waitFor(() => {
        expect(screen.getByTestId('create-task-modal')).toBeInTheDocument()
      })
    }
  })

  it('opens create task modal from empty state', async () => {
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('+ Добавить задачу')).toBeInTheDocument()
    })
    fireEvent.click(screen.getByText('+ Добавить задачу'))
    expect(screen.getByTestId('create-task-modal')).toBeInTheDocument()
  })

  it('closes create task modal', async () => {
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('+ Добавить задачу')).toBeInTheDocument()
    })
    fireEvent.click(screen.getByText('+ Добавить задачу'))
    expect(screen.getByTestId('create-task-modal')).toBeInTheDocument()
    fireEvent.click(screen.getByText('Close'))
    expect(screen.queryByTestId('create-task-modal')).not.toBeInTheDocument()
  })

  it('toggles task complete', async () => {
    tasksApi.complete.mockResolvedValue({ id: 1, completed: true })
    tasksApi.today.mockResolvedValue([mockTasks[0]])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Buy groceries')).toBeInTheDocument()
    })
    const buttons = document.querySelectorAll('button')
    const completeBtn = Array.from(buttons).find(b => b.className && b.className.includes('rounded-xl') && b.querySelector('span'))
    if (completeBtn) {
      fireEvent.click(completeBtn)
      await waitFor(() => {
        expect(tasksApi.complete).toHaveBeenCalledWith(1)
      })
    }
  })

  it('toggles uncomplete task - api setup', async () => {
    tasksApi.uncomplete.mockResolvedValue({ id: 2, completed: false })
    tasksApi.today.mockResolvedValue([mockTasks[0]])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Buy groceries')).toBeInTheDocument()
    })
    // Verify uncomplete api is mocked properly
    expect(tasksApi.uncomplete).toBeDefined()
  })

  it('shows habits with daily frequency', async () => {
    const dailyHabit = { id: 1, name: 'Daily Habit', frequency: 'daily', color: '#6366f1', icon: '💪', is_archived: false, created_at: '2026-01-01T00:00:00Z' }
    habitsApi.list.mockResolvedValue([dailyHabit])
    habitsApi.getLogs.mockResolvedValue([])
    habitsApi.getFreezes.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Daily Habit')).toBeInTheDocument()
    })
  })

  it('shows completion message when all habits done', async () => {
    const habit = { id: 1, name: 'Exercise', frequency: 'daily', color: '#6366f1', icon: '💪', is_archived: false, created_at: '2026-01-01T00:00:00Z' }
    habitsApi.list.mockResolvedValue([habit])
    const today = new Date().toISOString().split('T')[0]
    habitsApi.getLogs.mockResolvedValue([{ id: 10, date: today }])
    habitsApi.getFreezes.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText(/Все привычки выполнены/)).toBeInTheDocument()
    }, { timeout: 3000 })
  })

  it('opens log habit modal from calendar button', async () => {
    const habit = { id: 1, name: 'Exercise', frequency: 'daily', color: '#6366f1', icon: '💪', is_archived: false, created_at: '2026-01-01T00:00:00Z' }
    habitsApi.list.mockResolvedValue([habit])
    habitsApi.getLogs.mockResolvedValue([])
    habitsApi.getFreezes.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Exercise')).toBeInTheDocument()
    })
    const calendarBtn = document.querySelector('[title="Отметить за другой день"]')
    if (calendarBtn) {
      fireEvent.click(calendarBtn)
      await waitFor(() => {
        expect(screen.getByTestId('log-habit-modal')).toBeInTheDocument()
      })
    }
  })

  it('closes log habit modal', async () => {
    const habit = { id: 1, name: 'Exercise', frequency: 'daily', color: '#6366f1', icon: '💪', is_archived: false, created_at: '2026-01-01T00:00:00Z' }
    habitsApi.list.mockResolvedValue([habit])
    habitsApi.getLogs.mockResolvedValue([])
    habitsApi.getFreezes.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Exercise')).toBeInTheDocument()
    })
    const calendarBtn = document.querySelector('[title="Отметить за другой день"]')
    if (calendarBtn) {
      fireEvent.click(calendarBtn)
      await waitFor(() => {
        expect(screen.getByTestId('log-habit-modal')).toBeInTheDocument()
      })
      fireEvent.click(screen.getByText('Close'))
      expect(screen.queryByTestId('log-habit-modal')).not.toBeInTheDocument()
    }
  })

  it('handles habit toggle (log)', async () => {
    habitsApi.log.mockResolvedValue({ id: 99, date: new Date().toISOString().split('T')[0] })
    const habit = { id: 1, name: 'Exercise', frequency: 'daily', color: '#6366f1', icon: '💪', is_archived: false, created_at: '2026-01-01T00:00:00Z' }
    habitsApi.list.mockResolvedValue([habit])
    habitsApi.getLogs.mockResolvedValue([])
    habitsApi.getFreezes.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Exercise')).toBeInTheDocument()
    })
    const habitBtns = document.querySelectorAll('button.rounded-2xl')
    if (habitBtns.length > 0) {
      fireEvent.click(habitBtns[0])
      await waitFor(() => {
        expect(habitsApi.log).toHaveBeenCalledWith(1, {})
      })
    }
  })

  it('handles habit toggle (delete log when already done)', async () => {
    habitsApi.deleteLog.mockResolvedValue({})
    const habit = { id: 1, name: 'Exercise', frequency: 'daily', color: '#6366f1', icon: '💪', is_archived: false, created_at: '2026-01-01T00:00:00Z' }
    habitsApi.list.mockResolvedValue([habit])
    const today = new Date().toISOString().split('T')[0]
    habitsApi.getLogs.mockResolvedValue([{ id: 5, date: today }])
    habitsApi.getFreezes.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Exercise')).toBeInTheDocument()
    })
    // After logs load, find the undo button for habit
    await waitFor(() => {
      const undoBtns = document.querySelectorAll('[title="Отменить"]')
      expect(undoBtns.length).toBeGreaterThan(0)
    }, { timeout: 3000 })
  })

  it('renders tasks section header', async () => {
    tasksApi.today.mockResolvedValue([mockTasks[0]])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Задачи на сегодня')).toBeInTheDocument()
    })
  })

  it('handles log date from modal', async () => {
    habitsApi.log.mockResolvedValue({ id: 99, date: '2026-03-01' })
    const habit = { id: 1, name: 'Exercise', frequency: 'daily', color: '#6366f1', icon: '💪', is_archived: false, created_at: '2026-01-01T00:00:00Z' }
    habitsApi.list.mockResolvedValue([habit])
    habitsApi.getLogs.mockResolvedValue([])
    habitsApi.getFreezes.mockResolvedValue([])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText('Exercise')).toBeInTheDocument()
    })
    const calendarBtn = document.querySelector('[title="Отметить за другой день"]')
    if (calendarBtn) {
      fireEvent.click(calendarBtn)
      await waitFor(() => {
        expect(screen.getByTestId('log-habit-modal')).toBeInTheDocument()
      })
      fireEvent.click(screen.getByText('Log Date'))
      await waitFor(() => {
        expect(habitsApi.log).toHaveBeenCalledWith(1, { date: '2026-03-01' })
      })
    }
  })
})

// Test helper functions directly
describe('shouldShowToday helper', () => {
  it('renders frozen habit indicator when habit is frozen', async () => {
    const habit = { id: 1, name: 'Frozen Habit', frequency: 'daily', color: '#6366f1', icon: '❄️', is_archived: false, created_at: '2026-01-01T00:00:00Z' }
    habitsApi.list.mockResolvedValue([habit])
    habitsApi.getLogs.mockResolvedValue([])
    const today = new Date().toISOString().split('T')[0]
    // Create a freeze that covers today
    const yesterday = new Date()
    yesterday.setDate(yesterday.getDate() - 1)
    const tomorrow = new Date()
    tomorrow.setDate(tomorrow.getDate() + 1)
    habitsApi.getFreezes.mockResolvedValue([{
      start_date: yesterday.toISOString().split('T')[0],
      end_date: tomorrow.toISOString().split('T')[0]
    }])
    renderHome()
    await waitFor(() => {
      expect(screen.getByText(/паузе/)).toBeInTheDocument()
    }, { timeout: 3000 })
  })
})


