import { setActivePinia, createPinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { useChoreStore } from '../choreStore'
import type { Chore } from '@/types/chore'
import { apiClient } from '@/services/api'
import type { AxiosResponse } from 'axios'

// Mock choreService
vi.mock('@/services/choreService', () => ({
    choreService: {
        getPersonalChores: vi.fn(),
        getChores: vi.fn(),
        createChore: vi.fn(),
        updateChore: vi.fn(),
        deleteChore: vi.fn(),
    },
}))

import { choreService } from '@/services/choreService'

const mockSvc = choreService as unknown as {
    getPersonalChores: ReturnType<typeof vi.fn>
    getChores: ReturnType<typeof vi.fn>
    createChore: ReturnType<typeof vi.fn>
    updateChore: ReturnType<typeof vi.fn>
    deleteChore: ReturnType<typeof vi.fn>
}

// Helper to create a mock Axios response
const mockAxiosResponse = <T>(data: T): AxiosResponse<T> => ({
    data,
    status: 200,
    statusText: 'OK',
    headers: {},
    config: {} as any,
})

vi.mock('@/services/api', () => ({
    apiClient: {
        get: vi.fn(),
        post: vi.fn(),
        put: vi.fn(),
        delete: vi.fn(),
    },
    API_ENDPOINTS: {
        CHORES: {
            ASSIGNMENT_BY_ID: (id: number) => `/assignment/${id}`,
            TIME_ENTRY: (id: number) => `/time-entry/${id}`,
        }
    }
}));

describe('choreStore', () => {
    beforeEach(() => {
        setActivePinia(createPinia())
        vi.clearAllMocks()
        vi.mocked(apiClient.get).mockClear()
        vi.mocked(apiClient.post).mockClear()
        vi.mocked(apiClient.put).mockClear()
    })

    it('fetchPersonal populates personal chores', async () => {
        const mock: Chore[] = [
            {
                id: 1,
                name: 'Dishwashing',
                created_by_id: 1,
                frequency: 'daily',
                next_due_date: '',
                created_at: '',
                updated_at: '',
                type: 'personal',
                assignments: [],
            } as unknown as Chore,
        ]
        mockSvc.getPersonalChores.mockResolvedValue(mock)

        const store = useChoreStore()
        await store.fetchPersonal()

        expect(mockSvc.getPersonalChores).toHaveBeenCalled()
        expect(store.personal).toEqual(mock)
    })

    it('fetches time entries for an assignment', async () => {
        const store = useChoreStore()
        const assignmentId = 1
        const mockEntries = [{ id: 101, start_time: new Date().toISOString() }]
        vi.mocked(apiClient.get).mockResolvedValue(mockAxiosResponse(mockEntries))

        await store.fetchTimeEntries(assignmentId)

        expect(apiClient.get).toHaveBeenCalledWith(`/assignment/${assignmentId}/time-entries`)
        expect(store.timeEntriesByAssignment[assignmentId]).toEqual(mockEntries)
        expect(store.error).toBeNull()
    })

    it('starts a timer for an assignment', async () => {
        const store = useChoreStore()
        const assignmentId = 2
        const newEntry = { id: 102, start_time: new Date().toISOString(), assignment_id: assignmentId }
        vi.mocked(apiClient.post).mockResolvedValue(mockAxiosResponse(newEntry))

        const result = await store.startTimer(assignmentId)

        expect(apiClient.post).toHaveBeenCalledWith(`/assignment/${assignmentId}/time-entries`)
        expect(store.timeEntriesByAssignment[assignmentId]).toContainEqual(newEntry)
        expect(result).toEqual(newEntry)
    })

    it('stops a timer for a time entry', async () => {
        const store = useChoreStore()
        const assignmentId = 3
        const timeEntryId = 103
        const initialEntry = { id: timeEntryId, start_time: '2023-01-01T10:00:00Z', end_time: null, assignment_id: assignmentId }
        const updatedEntry = { ...initialEntry, end_time: new Date().toISOString() }

        store.timeEntriesByAssignment[assignmentId] = [initialEntry]
        vi.mocked(apiClient.put).mockResolvedValue(mockAxiosResponse(updatedEntry))

        const result = await store.stopTimer(assignmentId, timeEntryId)

        expect(apiClient.put).toHaveBeenCalledWith(`/time-entry/${timeEntryId}`)
        expect(store.timeEntriesByAssignment[assignmentId][0]).toEqual(updatedEntry)
        expect(result).toEqual(updatedEntry)
    })

    it('handles errors when fetching time entries', async () => {
        const store = useChoreStore()
        const assignmentId = 4
        vi.mocked(apiClient.get).mockRejectedValue(new Error('Network Error'))

        await store.fetchTimeEntries(assignmentId)

        expect(store.error).toContain('Failed to fetch time entries')
        expect(store.timeEntriesByAssignment[assignmentId]).toBeUndefined()
    })
}) 