/**
 * Neo Jalali DatePicker
 * یک DatePicker کاملاً سفارشی برای تقویم شمسی
 * نسخه: 1.0.0
 */

(function (global) {
    'use strict';

    // ============ توابع کمکی ============

    function toEnglishDigits(str) {
        var map = {
            '۰': '0', '۱': '1', '۲': '2', '۳': '3', '۴': '4',
            '۵': '5', '۶': '6', '۷': '7', '۸': '8', '۹': '9',
            '٠': '0', '١': '1', '٢': '2', '٣': '3', '٤': '4',
            '٥': '5', '٦': '6', '٧': '7', '٨': '8', '٩': '9'
        };
        return String(str || '').replace(/[۰-۹٠-٩]/g, function (d) { return map[d] || d; });
    }

    function isLikelyJalaliYear(year) {
        return year >= 1300 && year <= 1500;
    }

    function pad2(value) {
        return String(value).padStart(2, '0');
    }

    function extractDateParts(raw) {
        var clean = toEnglishDigits(raw || '').trim();
        if (!clean) return null;
        clean = clean.replace(/\./g, '/').replace(/-/g, '/');
        var parts = clean.split('/');
        if (parts.length !== 3) return null;
        var year = parseInt(parts[0], 10);
        var month = parseInt(parts[1], 10);
        var day = parseInt(parts[2], 10);
        if (!year || !month || !day) return null;
        return {
            year: year,
            month: month,
            day: day,
            normalized: String(year).padStart(4, '0') + '/' + pad2(month) + '/' + pad2(day)
        };
    }

    // ============ تبدیل تاریخ ============

    function gregorianToJalali(gy, gm, gd) {
        var g_d_m = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        var isLeap = (gy % 4 === 0 && gy % 100 !== 0) || (gy % 400 === 0);
        if (isLeap) g_d_m[2] = 29;
        var days = 355666 + (365 * gy) + Math.floor((gy + 3) / 4) - Math.floor((gy + 99) / 100) + Math.floor((gy + 399) / 400) + gd;
        for (var i = 0; i < gm; i++) {
            days += g_d_m[i];
        }
        var jy = -1595 + 33 * Math.floor(days / 12053);
        days %= 12053;
        jy += 4 * Math.floor(days / 1461);
        days %= 1461;
        if (days > 365) {
            jy += Math.floor((days - 1) / 365);
            days = (days - 1) % 365;
        }
        var jm, jd;
        if (days < 186) {
            jm = 1 + Math.floor(days / 31);
            jd = 1 + (days % 31);
        } else {
            jm = 7 + Math.floor((days - 186) / 30);
            jd = 1 + ((days - 186) % 30);
        }
        return [jy, jm, jd];
    }

    function jalaliToGregorian(jy, jm, jd) {
        var j_month_days = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29];
        jy = jy - 979;
        jm = jm - 1;
        jd = jd - 1;

        var j_day_no = 365 * jy + Math.floor(jy / 33) * 8 + Math.floor(((jy % 33) + 3) / 4);
        for (var i = 0; i < jm; ++i) {
            j_day_no += j_month_days[i];
        }
        j_day_no += jd;

        var g_day_no = j_day_no + 79;
        var gy = 1600 + 400 * Math.floor(g_day_no / 146097);
        g_day_no = g_day_no % 146097;

        var leap = true;
        if (g_day_no >= 36525) {
            g_day_no--;
            gy += 100 * Math.floor(g_day_no / 36524);
            g_day_no = g_day_no % 36524;

            if (g_day_no >= 365) {
                g_day_no++;
            } else {
                leap = false;
            }
        }

        gy += 4 * Math.floor(g_day_no / 1461);
        g_day_no %= 1461;

        if (g_day_no >= 366) {
            leap = false;
            g_day_no--;
            gy += Math.floor(g_day_no / 365);
            g_day_no = g_day_no % 365;
        }

        var g_month_days = [31, (leap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        var gm = 0;
        for (gm = 0; gm < 12 && g_day_no >= g_month_days[gm]; gm++) {
            g_day_no -= g_month_days[gm];
        }
        var gd = g_day_no + 1;
        return [gy, gm + 1, gd];
    }

    function formatJalaliDateFromGregorian(dateObj) {
        if (!dateObj) return '';
        var gy = dateObj.getFullYear();
        var gm = dateObj.getMonth() + 1;
        var gd = dateObj.getDate();
        var parts = gregorianToJalali(gy, gm, gd);
        var jy = String(parts[0]).padStart(4, '0');
        var jm = String(parts[1]).padStart(2, '0');
        var jd = String(parts[2]).padStart(2, '0');
        return jy + '/' + jm + '/' + jd;
    }

    // ============ تقویم شمسی ============

    var jalaliMonthNames = [
        'فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور',
        'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند'
    ];

    function jalaliLeap(jy) {
        var breaks = [-61, 9, 38, 199, 426, 686, 756, 818, 1111, 1181, 1210, 1635, 2060, 2097, 2192, 2262, 2324, 2394, 2456, 3178];
        var bl = breaks.length;
        var jp = breaks[0];
        if (jy < jp || jy >= breaks[bl - 1]) return false;
        var jump = 0;
        var leapJ = -14;
        for (var i = 1; i < bl; i++) {
            var jm = breaks[i];
            jump = jm - jp;
            if (jy < jm) break;
            leapJ = leapJ + Math.floor(jump / 33) * 8 + Math.floor((jump % 33) / 4);
            jp = jm;
        }
        var n = jy - jp;
        leapJ = leapJ + Math.floor(n / 33) * 8 + Math.floor(((n % 33) + 3) / 4);
        if (jump % 33 === 4 && jump - n === 4) leapJ += 1;
        var leap = (((n + 1) % 33) - 1) % 4;
        if (leap === -1) leap = 4;
        return leap === 0;
    }

    function getJalaliMonthDays(jy, jm) {
        if (jm <= 6) return 31;
        if (jm <= 11) return 30;
        return jalaliLeap(jy) ? 30 : 29;
    }

    function getTodayJalali() {
        var now = new Date();
        var parts = gregorianToJalali(now.getFullYear(), now.getMonth() + 1, now.getDate());
        return { year: parts[0], month: parts[1], day: parts[2] };
    }

    function parseInputToJalali(value) {
        var raw = String(value || '').trim();
        if (!raw) return null;
        var parts = extractDateParts(raw);
        if (parts) {
            if (isLikelyJalaliYear(parts.year)) {
                return { year: parts.year, month: parts.month, day: parts.day };
            }
            if (parts.year >= 1900) {
                var converted = gregorianToJalali(parts.year, parts.month, parts.day);
                return { year: converted[0], month: converted[1], day: converted[2] };
            }
        }
        if (/^\d{4}-\d{2}-\d{2}/.test(raw)) {
            var gy = parseInt(raw.substring(0, 4), 10);
            var gm = parseInt(raw.substring(5, 7), 10);
            var gd = parseInt(raw.substring(8, 10), 10);
            var conv = gregorianToJalali(gy, gm, gd);
            return { year: conv[0], month: conv[1], day: conv[2] };
        }
        return null;
    }

    function formatJalaliValue(jy, jm, jd) {
        return String(jy).padStart(4, '0') + '/' + pad2(jm) + '/' + pad2(jd);
    }

    function normalizeJalaliInputValue(value) {
        var raw = String(value || '').trim();
        if (!raw) return '';
        var parts = extractDateParts(raw);
        if (parts) {
            if (isLikelyJalaliYear(parts.year)) {
                return parts.normalized;
            }
            if (parts.year >= 1900) {
                var dt = new Date(parts.year, parts.month - 1, parts.day);
                if (!isNaN(dt.getTime())) return formatJalaliDateFromGregorian(dt);
            }
        }
        if (/^\d{4}-\d{2}-\d{2}/.test(raw)) {
            var dt2 = new Date(raw.substring(0, 10));
            if (!isNaN(dt2.getTime())) return formatJalaliDateFromGregorian(dt2);
        }
        return raw;
    }

    // ============ رندر Picker ============

    function positionPicker(picker, input) {
        var rect = input.getBoundingClientRect();
        var pickerHeight = picker.offsetHeight || 300;
        var viewportHeight = window.innerHeight;
        var spaceBelow = viewportHeight - rect.bottom;
        var spaceAbove = rect.top;

        // اگر فضای کافی در پایین نیست، در بالا نمایش بده
        if (spaceBelow < pickerHeight && spaceAbove > pickerHeight) {
            picker.style.top = (window.scrollY + rect.top - pickerHeight - 6) + 'px';
        } else {
            picker.style.top = (window.scrollY + rect.bottom + 6) + 'px';
        }
        picker.style.left = (window.scrollX + rect.right - picker.offsetWidth) + 'px';
    }

    function renderJalaliPicker(picker, state) {
        var jy = state.year;
        var jm = state.month;
        var jd = state.day;
        var monthName = jalaliMonthNames[jm - 1] || '';
        var title = monthName + ' ' + jy;
        var firstG = jalaliToGregorian(jy, jm, 1);
        var jsDay = new Date(firstG[0], firstG[1] - 1, firstG[2]).getDay();
        var offset = (jsDay + 1) % 7;
        var daysInMonth = getJalaliMonthDays(jy, jm);
        var today = getTodayJalali();
        
        var html = '';
        html += '<div class="neo-jdp-header">';
        html += '<button type="button" class="neo-jdp-nav" data-action="prev">‹</button>';
        html += '<div class="neo-jdp-title">' + title + '</div>';
        html += '<button type="button" class="neo-jdp-nav" data-action="next">›</button>';
        html += '</div>';
        html += '<div class="neo-jdp-week">';
        var week = ['ش', 'ی', 'د', 'س', 'چ', 'پ', 'ج'];
        for (var w = 0; w < week.length; w++) {
            html += '<div class="neo-jdp-weekday">' + week[w] + '</div>';
        }
        html += '</div>';
        html += '<div class="neo-jdp-grid">';
        for (var i = 0; i < offset; i++) {
            html += '<div class="neo-jdp-empty"></div>';
        }
        for (var d = 1; d <= daysInMonth; d++) {
            var classes = 'neo-jdp-day';
            if (d === jd) classes += ' selected';
            if (d === today.day && jm === today.month && jy === today.year) classes += ' today';
            html += '<button type="button" class="' + classes + '" data-day="' + d + '">' + d + '</button>';
        }
        html += '</div>';
        
        picker.innerHTML = html;
        
        // اتصال event handlers با استفاده از event delegation
        picker.onclick = function(ev) {
            var target = ev.target;
            
            // کلیک روی دکمه‌های navigation
            if (target.classList.contains('neo-jdp-nav')) {
                ev.preventDefault();
                ev.stopPropagation();
                
                var action = target.getAttribute('data-action');
                if (action === 'prev') {
                    var month = state.month - 1;
                    var year = state.year;
                    if (month < 1) {
                        month = 12;
                        year -= 1;
                    }
                    state.year = year;
                    state.month = month;
                    state.day = Math.min(state.day, getJalaliMonthDays(year, month));
                    renderJalaliPicker(picker, state);
                } else if (action === 'next') {
                    var month = state.month + 1;
                    var year = state.year;
                    if (month > 12) {
                        month = 1;
                        year += 1;
                    }
                    state.year = year;
                    state.month = month;
                    state.day = Math.min(state.day, getJalaliMonthDays(year, month));
                    renderJalaliPicker(picker, state);
                }
            }
            
            // کلیک روی روزها
            else if (target.classList.contains('neo-jdp-day')) {
                ev.preventDefault();
                ev.stopPropagation();
                
                var day = parseInt(target.getAttribute('data-day'), 10);
                state.day = day;
                var formatted = formatJalaliValue(state.year, state.month, state.day);
                state.input.value = formatted;
                
                // فراخوانی callback اگر وجود داشت
                if (typeof state.onSelect === 'function') {
                    state.onSelect(formatted);
                }
                
                // ارسال events
                state.input.dispatchEvent(new Event('input', { bubbles: true }));
                state.input.dispatchEvent(new Event('change', { bubbles: true }));
                
                // بستن picker
                state.close();
            }
        };
    }

    // ============ تابع اصلی Initialize ============

    function initJalaliPicker(input, onSelect) {
        if (!input) return;
        input.removeAttribute('readonly');
        
        var normalizedValue = normalizeJalaliInputValue(input.value);
        if (normalizedValue) {
            input.value = normalizedValue;
        }
        
        // اگر قبلاً initialize شده، فقط callback را update کن
        if (input._neoJdp) {
            if (onSelect) input._neoJdp.onSelect = onSelect;
            return input._neoJdp;
        }
        
        var picker = document.createElement('div');
        picker.className = 'neo-jdp';
        picker.style.display = 'none';
        document.body.appendChild(picker);
        
        var state = {
            input: input,
            picker: picker,
            onSelect: onSelect,
            year: 0,
            month: 0,
            day: 0,
            close: function () {
                picker.style.display = 'none';
            },
            destroy: function () {
                if (picker.parentNode) {
                    picker.parentNode.removeChild(picker);
                }
                delete input._neoJdp;
            }
        };
        
        function openPicker() {
            var parsed = parseInputToJalali(input.value) || getTodayJalali();
            state.year = parsed.year;
            state.month = parsed.month;
            state.day = parsed.day;
            renderJalaliPicker(picker, state);
            picker.style.display = 'block';
            positionPicker(picker, input);
        }
        
        input.addEventListener('focus', openPicker);
        input.addEventListener('click', openPicker);
        
        document.addEventListener('click', function (ev) {
            if (ev.target === input || picker.contains(ev.target)) return;
            state.close();
        });
        
        input._neoJdp = state;
        return state;
    }

    // ============ Export به Global ============

    global.NeoJalaliDatePicker = {
        init: initJalaliPicker,
        gregorianToJalali: gregorianToJalali,
        jalaliToGregorian: jalaliToGregorian,
        formatJalaliDateFromGregorian: formatJalaliDateFromGregorian,
        getTodayJalali: getTodayJalali,
        version: '1.0.0'
    };

    // برای سازگاری با کدهای قبلی
    global.initJalaliPicker = initJalaliPicker;

})(window);

