import { describe, it, expect, beforeEach, vi } from 'vitest';
import { useAuthStore } from '@/stores/authStore';

const initial = useAuthStore.getInitialState();

function jsonRes(body: unknown, ok = true): Response {
    return { ok, json: () => Promise.resolve(body) } as unknown as Response;
}

beforeEach(() => {
    localStorage.clear();
    useAuthStore.setState(initial, true);
    vi.stubGlobal('fetch', vi.fn().mockResolvedValue(jsonRes({ success: false })));
});

describe('login', () => {
    it('توکن را ست و isAuthenticated را true می‌کند', () => {
        useAuthStore.getState().login('tok', 'refresh');
        const s = useAuthStore.getState();
        expect(s.token).toBe('tok');
        expect(s.refreshToken).toBe('refresh');
        expect(s.isAuthenticated).toBe(true);
    });
    it('fetchMe (userinfo) را صدا می‌زند', () => {
        useAuthStore.getState().login('tok');
        expect(fetch).toHaveBeenCalledWith('/oauth/userinfo', expect.any(Object));
    });
});

describe('logout', () => {
    it('state را پاک می‌کند و وقتی refreshToken هست به /oauth/logout POST می‌زند', () => {
        useAuthStore.setState({ token: 'tok', refreshToken: 'rt', isAuthenticated: true });
        useAuthStore.getState().logout();
        const s = useAuthStore.getState();
        expect(s.token).toBeNull();
        expect(s.isAuthenticated).toBe(false);
        expect(fetch).toHaveBeenCalledWith('/oauth/logout', expect.objectContaining({ method: 'POST' }));
    });
});

describe('refresh', () => {
    it('بدون refreshToken → null و بدون fetch', async () => {
        const out = await useAuthStore.getState().refresh();
        expect(out).toBeNull();
        expect(fetch).not.toHaveBeenCalled();
    });
    it('پاسخ موفق → توکن جدید برمی‌گرداند و state را به‌روز می‌کند', async () => {
        useAuthStore.setState({ refreshToken: 'rt' });
        (fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
            jsonRes({ access_token: 'new-tok', refresh_token: 'new-rt' }),
        );
        const out = await useAuthStore.getState().refresh();
        expect(out).toBe('new-tok');
        expect(useAuthStore.getState().token).toBe('new-tok');
        expect(useAuthStore.getState().refreshToken).toBe('new-rt');
    });
    it('پاسخ بدون access_token → null', async () => {
        useAuthStore.setState({ refreshToken: 'rt' });
        (fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(jsonRes({}, false));
        expect(await useAuthStore.getState().refresh()).toBeNull();
    });
});

describe('fetchMe', () => {
    it('userinfo موفق → فیلدهای کاربر را ست می‌کند', async () => {
        (fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
            jsonRes({
                success: true,
                data: {
                    uuid: 'u1',
                    realName: 'دکتر تست',
                    primary_role: 'doctor',
                    available_contexts: [{ type: 'doctor', db_uuid: 'd1', name: 'مطب', role: 'doctor' }],
                },
            }),
        );
        await useAuthStore.getState().fetchMe();
        const s = useAuthStore.getState();
        expect(s.userUuid).toBe('u1');
        expect(s.userName).toBe('دکتر تست');
        expect(s.primaryRole).toBe('doctor');
        expect(s.availableContexts).toHaveLength(1);
    });
});

describe('switchContext', () => {
    it('پاسخ موفق → db و context و primaryRole را ست می‌کند', async () => {
        (fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
            jsonRes({
                success: true,
                data: {
                    db_uuid: 'db2',
                    db_key: 'key2',
                    context: { type: 'clinic', db_uuid: 'db2', name: 'کلینیک', role: 'clinic', doctor_uuid: 'doc9' },
                },
            }),
        );
        await useAuthStore.getState().switchContext('db2');
        const s = useAuthStore.getState();
        expect(s.dbUuid).toBe('db2');
        expect(s.dbKey).toBe('key2');
        expect(s.primaryRole).toBe('clinic');
        expect(s.doctorUuid).toBe('doc9');
    });
});
