import { describe, it, expect, vi, beforeEach } from 'vitest'

vi.mock('../api/client', () => ({
  default: {
    get: vi.fn(),
    post: vi.fn(),
    put: vi.fn(),
    delete: vi.fn(),
    interceptors: {
      request: { use: vi.fn() },
      response: { use: vi.fn() },
    },
  },
}))

import api from '../api/client'
import { tasksApi } from '../api/tasks'
import { habitsApi } from '../api/habits'
import { savingsApi } from '../api/savings'
import { profileApi } from '../api/profile'

describe('tasksApi', () => {
  beforeEach(() => vi.clearAllMocks())

  it('should list all tasks', async () => {
    api.get.mockResolvedValueOnce({ data: [{ id: 1, title: 'Test' }] })
    const result = await tasksApi.list()
    expect(api.get).toHaveBeenCalledWith('tasks')
    expect(result).toEqual([{ id: 1, title: 'Test' }])
  })

  it('should list completed tasks', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await tasksApi.list(true)
    expect(api.get).toHaveBeenCalledWith('tasks?completed=true')
  })

  it('should list incomplete tasks', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await tasksApi.list(false)
    expect(api.get).toHaveBeenCalledWith('tasks?completed=false')
  })

  it('should get today tasks', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await tasksApi.today()
    expect(api.get).toHaveBeenCalledWith('tasks/today')
  })

  it('should create a task', async () => {
    const taskData = { title: 'New Task', priority: 1 }
    api.post.mockResolvedValueOnce({ data: { id: 1, ...taskData } })
    const result = await tasksApi.create(taskData)
    expect(api.post).toHaveBeenCalledWith('tasks', taskData)
    expect(result.title).toBe('New Task')
  })

  it('should update a task', async () => {
    api.put.mockResolvedValueOnce({ data: { id: 1, title: 'Updated' } })
    await tasksApi.update(1, { title: 'Updated' })
    expect(api.put).toHaveBeenCalledWith('tasks/1', { title: 'Updated' })
  })

  it('should delete a task', async () => {
    api.delete.mockResolvedValueOnce({})
    await tasksApi.delete(1)
    expect(api.delete).toHaveBeenCalledWith('tasks/1')
  })

  it('should complete a task', async () => {
    api.post.mockResolvedValueOnce({ data: { id: 1, completed: true } })
    await tasksApi.complete(1)
    expect(api.post).toHaveBeenCalledWith('tasks/1/complete')
  })

  it('should uncomplete a task', async () => {
    api.post.mockResolvedValueOnce({ data: { id: 1, completed: false } })
    await tasksApi.uncomplete(1)
    expect(api.post).toHaveBeenCalledWith('tasks/1/uncomplete')
  })

  it('should get a single task', async () => {
    api.get.mockResolvedValueOnce({ data: { id: 5, title: 'Task 5' } })
    const result = await tasksApi.get(5)
    expect(api.get).toHaveBeenCalledWith('tasks/5')
    expect(result.id).toBe(5)
  })
})

describe('habitsApi', () => {
  beforeEach(() => vi.clearAllMocks())

  it('should list habits', async () => {
    api.get.mockResolvedValueOnce({ data: [{ id: 1, name: 'Exercise' }] })
    const result = await habitsApi.list()
    expect(api.get).toHaveBeenCalledWith('/habits')
    expect(result).toEqual([{ id: 1, name: 'Exercise' }])
  })

  it('should create a habit', async () => {
    api.post.mockResolvedValueOnce({ data: { id: 1, name: 'Read' } })
    await habitsApi.create({ name: 'Read' })
    expect(api.post).toHaveBeenCalledWith('/habits', { name: 'Read' })
  })

  it('should update a habit', async () => {
    api.put.mockResolvedValueOnce({ data: { id: 1, name: 'Updated' } })
    await habitsApi.update(1, { name: 'Updated' })
    expect(api.put).toHaveBeenCalledWith('/habits/1', { name: 'Updated' })
  })

  it('should log a habit', async () => {
    api.post.mockResolvedValueOnce({ data: { id: 1 } })
    await habitsApi.log(5, { date: '2025-03-01' })
    expect(api.post).toHaveBeenCalledWith('/habits/5/log', { date: '2025-03-01' })
  })

  it('should log habit with empty data', async () => {
    api.post.mockResolvedValueOnce({ data: { id: 1 } })
    await habitsApi.log(5)
    expect(api.post).toHaveBeenCalledWith('/habits/5/log', {})
  })

  it('should get logs with custom days', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await habitsApi.getLogs(5, 60)
    expect(api.get).toHaveBeenCalledWith('/habits/5/logs?days=60')
  })

  it('should get overall stats', async () => {
    api.get.mockResolvedValueOnce({ data: { total_habits: 5 } })
    await habitsApi.getStats()
    expect(api.get).toHaveBeenCalledWith('/habits/stats')
  })

  it('should get single habit stats', async () => {
    api.get.mockResolvedValueOnce({ data: { habit_id: 3 } })
    await habitsApi.getHabitStats(3)
    expect(api.get).toHaveBeenCalledWith('/habits/3/stats')
  })

  it('should get freezes', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await habitsApi.getFreezes(3)
    expect(api.get).toHaveBeenCalledWith('/habits/3/freezes')
  })

  it('should add freeze', async () => {
    const freezeData = { start_date: '2025-03-01', end_date: '2025-03-07' }
    api.post.mockResolvedValueOnce({ data: { id: 1 } })
    await habitsApi.addFreeze(3, freezeData)
    expect(api.post).toHaveBeenCalledWith('/habits/3/freezes', freezeData)
  })

  it('should delete freeze', async () => {
    api.delete.mockResolvedValueOnce({})
    await habitsApi.deleteFreeze(3, 10)
    expect(api.delete).toHaveBeenCalledWith('/habits/3/freezes/10')
  })

  it('should delete a habit', async () => {
    api.delete.mockResolvedValueOnce({})
    await habitsApi.delete(5)
    expect(api.delete).toHaveBeenCalledWith('/habits/5')
  })

  it('should delete a log', async () => {
    api.delete.mockResolvedValueOnce({})
    await habitsApi.deleteLog(3, 7)
    expect(api.delete).toHaveBeenCalledWith('/habits/3/logs/7')
  })
})

describe('savingsApi', () => {
  beforeEach(() => vi.clearAllMocks())

  it('should list categories', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await savingsApi.listCategories()
    expect(api.get).toHaveBeenCalledWith('/savings/categories')
  })

  it('should get single category', async () => {
    api.get.mockResolvedValueOnce({ data: { id: 1 } })
    await savingsApi.getCategory(1)
    expect(api.get).toHaveBeenCalledWith('/savings/categories/1')
  })

  it('should create category', async () => {
    api.post.mockResolvedValueOnce({ data: { id: 1 } })
    await savingsApi.createCategory({ name: 'Savings' })
    expect(api.post).toHaveBeenCalledWith('/savings/categories', { name: 'Savings' })
  })

  it('should update category', async () => {
    api.put.mockResolvedValueOnce({ data: { id: 1 } })
    await savingsApi.updateCategory(1, { name: 'Updated' })
    expect(api.put).toHaveBeenCalledWith('/savings/categories/1', { name: 'Updated' })
  })

  it('should delete category', async () => {
    api.delete.mockResolvedValueOnce({})
    await savingsApi.deleteCategory(1)
    expect(api.delete).toHaveBeenCalledWith('/savings/categories/1')
  })

  it('should create transaction', async () => {
    const data = { category_id: 1, amount: 1000, type: 'deposit', date: '2025-03-01' }
    api.post.mockResolvedValueOnce({ data: { id: 1 } })
    await savingsApi.createTransaction(data)
    expect(api.post).toHaveBeenCalledWith('/savings/transactions', data)
  })

  it('should list transactions with category filter', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await savingsApi.listTransactions(5, 50, 10)
    expect(api.get).toHaveBeenCalledWith('/savings/transactions?limit=50&offset=10&category_id=5')
  })

  it('should list transactions without category filter', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await savingsApi.listTransactions(null)
    expect(api.get).toHaveBeenCalledWith('/savings/transactions?limit=100&offset=0')
  })

  it('should get stats', async () => {
    api.get.mockResolvedValueOnce({ data: { total_balance: 5000 } })
    await savingsApi.getStats()
    expect(api.get).toHaveBeenCalledWith('/savings/stats')
  })

  it('should get members', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await savingsApi.getMembers(1)
    expect(api.get).toHaveBeenCalledWith('/savings/categories/1/members')
  })

  it('should add member', async () => {
    api.post.mockResolvedValueOnce({ data: [] })
    await savingsApi.addMember(1, 42)
    expect(api.post).toHaveBeenCalledWith('/savings/categories/1/members', { user_id: 42 })
  })

  it('should get recurring plans', async () => {
    api.get.mockResolvedValueOnce({ data: [] })
    await savingsApi.getRecurringPlans(1)
    expect(api.get).toHaveBeenCalledWith('/savings/categories/1/recurring-plans')
  })
})

describe('profileApi', () => {
  beforeEach(() => vi.clearAllMocks())

  it('should get profile', async () => {
    api.get.mockResolvedValueOnce({ data: { username: 'test' } })
    const result = await profileApi.get()
    expect(api.get).toHaveBeenCalledWith('/profile')
    expect(result.username).toBe('test')
  })

  it('should update profile', async () => {
    api.put.mockResolvedValueOnce({ data: { username: 'updated' } })
    const result = await profileApi.update({ username: 'updated' })
    expect(api.put).toHaveBeenCalledWith('/profile', { username: 'updated' })
    expect(result.username).toBe('updated')
  })
})
