import { describe, it, expect, beforeEach } from 'vitest';
import { adaptSlots, hasAvailable } from '@/lib/appointmentSlots';
import { getAccessToken, setAccessToken, clearAccessToken } from '@/lib/tokenStore';
import { sanitizeHtml, safeJsonParse } from '@/lib/sanitize';
import { defineAbilitiesFor } from '@/lib/ability';
import { setRefreshCookie, clearRefreshCookie, COOKIE_NAME } from '@/lib/refreshCookie';
import { buildPatientUser } from '@/lib/representationAdapters';

describe('appointmentSlots', () => {
    const resp = {
        sessions: [
            { slots: [
                { start_time: '09:00', is_available: true },
                { start_time: '11:30', is_available: false },
                { start_time: '14:00', is_available: true },
            ] },
        ],
    };
    it('adaptSlots اسلات‌ها را بر اساس 12:00 به صبح/عصر تقسیم می‌کند', () => {
        const { morning, evening } = adaptSlots(resp);
        expect(morning).toHaveLength(2);
        expect(evening).toHaveLength(1);
        expect(evening[0].start_time).toBe('14:00');
    });
    it('ساختار data.sessions را هم می‌پذیرد', () => {
        const { morning } = adaptSlots({ data: resp });
        expect(morning).toHaveLength(2);
    });
    it('ورودی خالی → آرایه‌های خالی', () => {
        expect(adaptSlots(null)).toEqual({ morning: [], evening: [] });
    });
    it('hasAvailable', () => {
        expect(hasAvailable([{ is_available: false }, { is_available: true }])).toBe(true);
        expect(hasAvailable([{ is_available: false }])).toBe(false);
        expect(hasAvailable([])).toBe(false);
        expect(hasAvailable(null)).toBe(false);
    });
});

describe('tokenStore', () => {
    beforeEach(() => clearAccessToken());
    it('set/get/clear', () => {
        expect(getAccessToken()).toBeNull();
        setAccessToken('tok');
        expect(getAccessToken()).toBe('tok');
        clearAccessToken();
        expect(getAccessToken()).toBeNull();
    });
    it('set با مقدار falsy → null', () => {
        setAccessToken('');
        expect(getAccessToken()).toBeNull();
    });
});

describe('sanitize', () => {
    it('غیررشته → رشته خالی', () => {
        expect(sanitizeHtml(null)).toBe('');
        expect(sanitizeHtml(123)).toBe('');
    });
    it('تگ مجاز حفظ، اسکریپت حذف', () => {
        const out = sanitizeHtml('<p>سلام</p><script>alert(1)</script>');
        expect(out).toContain('<p>سلام</p>');
        expect(out).not.toContain('<script>');
    });
    it('safeJsonParse معتبر → object', () => {
        expect(safeJsonParse('{"a":1}')).toEqual({ a: 1 });
    });
    it('safeJsonParse نامعتبر → fallback', () => {
        expect(safeJsonParse('{bad', { x: 1 })).toEqual({ x: 1 });
        expect(safeJsonParse('')).toBeNull();
    });
});

describe('ability (CASL)', () => {
    it('کاربر لاگین → دسترسی Dashboard، نه Login', () => {
        const a = defineAbilitiesFor({ id: 1 });
        expect(a.can('access', 'Dashboard')).toBe(true);
        expect(a.can('access', 'Login')).toBe(false);
    });
    it('بدون کاربر → دسترسی Login، نه Dashboard', () => {
        const a = defineAbilitiesFor(null);
        expect(a.can('access', 'Login')).toBe(true);
        expect(a.can('access', 'Dashboard')).toBe(false);
    });
});

describe('refreshCookie (cookieDomain از طریق set)', () => {
    let response;
    beforeEach(() => {
        response = { cookies: { set: vi.fn() } };
    });
    it('دامنه‌ی واقعی → "." + دو لیبل آخر', () => {
        setRefreshCookie(response, 'rt', 'arak-nobat.ir');
        const opts = response.cookies.set.mock.calls[0][2];
        expect(response.cookies.set.mock.calls[0][0]).toBe(COOKIE_NAME);
        expect(opts.domain).toBe('.arak-nobat.ir');
        expect(opts.httpOnly).toBe(true);
    });
    it('host سه‌لیبلی → فقط دو لیبل آخر', () => {
        setRefreshCookie(response, 'rt', 'www.arak-nobat.ir');
        expect(response.cookies.set.mock.calls[0][2].domain).toBe('.arak-nobat.ir');
    });
    it('localhost و IP → domain undefined', () => {
        setRefreshCookie(response, 'rt', 'localhost:3000');
        expect(response.cookies.set.mock.calls[0][2].domain).toBeUndefined();
        response.cookies.set.mockClear();
        setRefreshCookie(response, 'rt', '127.0.0.1');
        expect(response.cookies.set.mock.calls[0][2].domain).toBeUndefined();
    });
    it('clearRefreshCookie با maxAge=0', () => {
        clearRefreshCookie(response, 'arak-nobat.ir');
        expect(response.cookies.set.mock.calls[0][2].maxAge).toBe(0);
    });
});

describe('representationAdapters.buildPatientUser', () => {
    it('ساختار double-nested را flatten می‌کند', () => {
        const out = buildPatientUser({
            data: { data: { label: 'علی', family: 'رضایی', phone: '09120000000', national_code: '0013542419' } },
        });
        expect(out.name).toBe('علی رضایی');
        expect(out.phone).toBe('09120000000');
        expect(out.national_code).toBe('0013542419');
    });
    it('ورودی خالی → مقادیر پیش‌فرض', () => {
        const out = buildPatientUser(null);
        expect(out.name).toBe('');
        expect(out.profile).toBe('/assets/images/profile-user.png');
        expect(out.turns).toEqual({ current: [], done: [] });
    });
    it('extras به‌عنوان fallback استفاده می‌شود', () => {
        const out = buildPatientUser({}, { realName: 'مهمان', mobile: '0935' });
        expect(out.name).toBe('مهمان');
        expect(out.phone).toBe('0935');
    });
});
