import { describe, it, expect } from 'vitest';
import {
    formatRial,
    rialToToman,
    tomanToRial,
    formatNumber,
    toDate,
    formatDate,
    formatDateTime,
    toGregorianDate,
    maskMobile,
    cn,
    toEnglishDigits,
    sanitizeMobileInput,
    isValidIranMobile,
    IRAN_MOBILE_RE,
    iranMobileSchema,
    iranMobileOptionalSchema,
} from '@/lib/utils';

const PERSIAN_DIGITS = /[۰-۹]/;

describe('formatRial', () => {
    it('مقدار ریال را ÷۱۰ به تومان تبدیل و با پسوند تومان برمی‌گرداند', () => {
        const out = formatRial(150000); // ۱۵۰٬۰۰۰ ریال = ۱۵٬۰۰۰ تومان
        expect(out).toContain('تومان');
        expect(out).toMatch(PERSIAN_DIGITS);
        expect(out).toContain(new Intl.NumberFormat('fa-IR').format(15000));
    });
    it('صفر را هم فرمت می‌کند', () => {
        expect(formatRial(0)).toContain('تومان');
    });
});

describe('rialToToman / tomanToRial', () => {
    it('ریال↔تومان با ضریب ۱۰', () => {
        expect(rialToToman(150000)).toBe(15000);
        expect(tomanToRial(15000)).toBe(150000);
        expect(tomanToRial(rialToToman(500))).toBe(500);
    });
});

describe('formatNumber', () => {
    it('رقم فارسی برمی‌گرداند', () => {
        expect(formatNumber(1234)).toMatch(PERSIAN_DIGITS);
    });
});

describe('toDate', () => {
    it('null و رشته خالی → null', () => {
        expect(toDate(null)).toBeNull();
        expect(toDate(undefined)).toBeNull();
        expect(toDate('')).toBeNull();
    });
    it('عدد را به‌عنوان ثانیه (×۱۰۰۰) تفسیر می‌کند', () => {
        const d = toDate(1_700_000_000);
        expect(d).toBeInstanceOf(Date);
        expect(d!.getTime()).toBe(1_700_000_000 * 1000);
    });
    it('Y-m-d را ظهر محلی می‌گیرد (نه نیمه‌شب UTC)', () => {
        const d = toDate('2024-03-21');
        expect(d!.getHours()).toBe(12);
        expect(d!.getFullYear()).toBe(2024);
    });
    it('رشته ISO کامل را پارس می‌کند', () => {
        const d = toDate('2024-03-21T08:30:00Z');
        expect(d).toBeInstanceOf(Date);
        expect(isNaN(d!.getTime())).toBe(false);
    });
});

describe('formatDate', () => {
    it('ورودی نامعتبر → "—"', () => {
        expect(formatDate(null)).toBe('—');
        expect(formatDate('not-a-date')).toBe('—');
    });
    it('timestamp ثانیه‌ای معتبر → رشته شمسی با رقم فارسی', () => {
        const out = formatDate(1_700_000_000);
        expect(out).not.toBe('—');
        expect(out).toMatch(PERSIAN_DIGITS);
    });
});

describe('formatDateTime', () => {
    it('ورودی نامعتبر → "—"', () => {
        expect(formatDateTime(undefined)).toBe('—');
    });
    it('معتبر → شامل ساعت و رقم فارسی', () => {
        const out = formatDateTime(1_700_000_000);
        expect(out).not.toBe('—');
        expect(out).toMatch(PERSIAN_DIGITS);
    });
});

describe('toGregorianDate', () => {
    it('YYYY-MM-DD با صفر پیش‌رو', () => {
        expect(toGregorianDate(new Date(2024, 0, 5))).toBe('2024-01-05');
        expect(toGregorianDate(new Date(2024, 11, 31))).toBe('2024-12-31');
    });
});

describe('maskMobile', () => {
    it('شماره ۱۱ رقمی را ماسک می‌کند', () => {
        expect(maskMobile('09123456789')).toBe('0912***789');
    });
    it('شماره کوتاه‌تر از ۷ رقم بدون تغییر', () => {
        expect(maskMobile('123')).toBe('123');
    });
});

describe('cn', () => {
    it('مقادیر falsy را حذف و بقیه را با فاصله می‌چسباند', () => {
        expect(cn('a', false, null, undefined, 'b')).toBe('a b');
        expect(cn()).toBe('');
    });
});

describe('toEnglishDigits', () => {
    it('رقم فارسی به انگلیسی', () => {
        expect(toEnglishDigits('۰۹۱۲۳۴۵۶۷۸۹')).toBe('09123456789');
    });
    it('رقم عربی به انگلیسی', () => {
        expect(toEnglishDigits('٠٩١٢')).toBe('0912');
    });
    it('ورودی خالی → رشته خالی', () => {
        expect(toEnglishDigits('')).toBe('');
    });
    it('کاراکترهای غیررقمی را دست‌نخورده نگه می‌دارد', () => {
        expect(toEnglishDigits('شماره ۰۹')).toBe('شماره 09');
    });
});

describe('sanitizeMobileInput', () => {
    it('غیررقم حذف، رقم فارسی نرمال، حداکثر ۱۱ رقم', () => {
        expect(sanitizeMobileInput('۰۹۱۲-۳۴۵ ۶۷۸۹۰۱۲')).toBe('09123456789');
    });
    it('فقط حروف → خالی', () => {
        expect(sanitizeMobileInput('abc')).toBe('');
    });
});

describe('isValidIranMobile / IRAN_MOBILE_RE', () => {
    it.each([
        ['09123456789', true],
        ['۰۹۱۲۳۴۵۶۷۸۹', true],
        ['9123456789', false],
        ['08123456789', false],
        ['0912345678', false],
        ['091234567890', false],
    ])('%s → %s', (input, expected) => {
        expect(isValidIranMobile(input as string)).toBe(expected);
    });
    it('regex مستقیم روی ارقام انگلیسی', () => {
        expect(IRAN_MOBILE_RE.test('09120000000')).toBe(true);
    });
});

describe('iranMobileSchema', () => {
    it('رقم فارسی را پذیرفته و نرمال می‌کند', () => {
        expect(iranMobileSchema.parse('۰۹۱۲۳۴۵۶۷۸۹')).toBe('09123456789');
    });
    it('جداکننده‌ها را حذف می‌کند', () => {
        expect(iranMobileSchema.parse('0912-345-6789')).toBe('09123456789');
    });
    it('شماره نامعتبر → ناموفق', () => {
        const r = iranMobileSchema.safeParse('12345');
        expect(r.success).toBe(false);
    });
});

describe('iranMobileOptionalSchema', () => {
    it('رشته خالی مجاز است', () => {
        expect(iranMobileOptionalSchema.parse('')).toBe('');
    });
    it('شماره معتبر نرمال می‌شود', () => {
        expect(iranMobileOptionalSchema.parse('۰۹۱۲۳۴۵۶۷۸۹')).toBe('09123456789');
    });
    it('شماره نیمه‌کاره → ناموفق', () => {
        expect(iranMobileOptionalSchema.safeParse('0912').success).toBe(false);
    });
});
