export type StatsPreset = 'custom' | 'today' | 'yesterday' | 'last7' | 'last14' | 'last30';

export interface DateRange {
    from: string;
    to: string;
}

export const STATS_PRESET_OPTIONS: { id: StatsPreset; label: string }[] = [
    { id: 'custom', label: 'Custom' },
    { id: 'today', label: 'Today' },
    { id: 'yesterday', label: 'Yesterday' },
    { id: 'last7', label: 'Last 7 days' },
    { id: 'last14', label: 'Last 14 days' },
    { id: 'last30', label: 'Last 30 days' },
];

const WIB_OFFSET_MS = 7 * 60 * 60 * 1000;

interface DateParts {
    year: number;
    month: number;
    day: number;
}

function getWibTodayParts(): DateParts {
    const wib = new Date(Date.now() + WIB_OFFSET_MS);
    return {
        year: wib.getUTCFullYear(),
        month: wib.getUTCMonth(),
        day: wib.getUTCDate(),
    };
}

function partsToDateString(parts: DateParts): string {
    const month = String(parts.month + 1).padStart(2, '0');
    const day = String(parts.day).padStart(2, '0');
    return `${parts.year}-${month}-${day}`;
}

function parseDateOnly(value: string): DateParts | null {
    const match = String(value).trim().match(/^(\d{4})-(\d{2})-(\d{2})/);
    if (!match) return null;
    return {
        year: Number(match[1]),
        month: Number(match[2]) - 1,
        day: Number(match[3]),
    };
}

function addDays(parts: DateParts, days: number): DateParts {
    const date = new Date(Date.UTC(parts.year, parts.month, parts.day));
    date.setUTCDate(date.getUTCDate() + days);
    return {
        year: date.getUTCFullYear(),
        month: date.getUTCMonth(),
        day: date.getUTCDate(),
    };
}

export function getPresetRange(preset: Exclude<StatsPreset, 'custom'>): DateRange {
    const today = getWibTodayParts();

    switch (preset) {
        case 'today':
            return { from: partsToDateString(today), to: partsToDateString(today) };
        case 'yesterday': {
            const yesterday = addDays(today, -1);
            return { from: partsToDateString(yesterday), to: partsToDateString(yesterday) };
        }
        case 'last7':
            return { from: partsToDateString(addDays(today, -6)), to: partsToDateString(today) };
        case 'last14':
            return { from: partsToDateString(addDays(today, -13)), to: partsToDateString(today) };
        case 'last30':
            return { from: partsToDateString(addDays(today, -29)), to: partsToDateString(today) };
        default:
            return getPresetRange('last7');
    }
}

export function getDefaultStatsDateRange(): DateRange {
    return getPresetRange('last7');
}

export function inclusiveDays(from: string, to: string): number {
    const fromParts = parseDateOnly(from);
    const toParts = parseDateOnly(to);
    if (!fromParts || !toParts) return 1;

    const start = Date.UTC(fromParts.year, fromParts.month, fromParts.day);
    const end = Date.UTC(toParts.year, toParts.month, toParts.day);
    const diff = Math.floor((end - start) / (24 * 60 * 60 * 1000));
    return Math.max(diff + 1, 1);
}

export function getPreviousPeriodRange(range: DateRange): DateRange {
    const lengthDays = inclusiveDays(range.from, range.to);
    const fromParts = parseDateOnly(range.from);
    if (!fromParts) return range;

    const previousTo = addDays(fromParts, -1);
    const previousFrom = addDays(previousTo, -(lengthDays - 1));

    return {
        from: partsToDateString(previousFrom),
        to: partsToDateString(previousTo),
    };
}

export function detectPresetFromRange(range: DateRange): StatsPreset {
    for (const preset of ['today', 'yesterday', 'last7', 'last14', 'last30'] as const) {
        const presetRange = getPresetRange(preset);
        if (presetRange.from === range.from && presetRange.to === range.to) {
            return preset;
        }
    }
    return 'custom';
}

export function formatDisplayDate(dateStr: string): string {
    const parts = parseDateOnly(dateStr);
    if (!parts) return dateStr;

    const date = new Date(Date.UTC(parts.year, parts.month, parts.day));
    return date.toLocaleDateString('en-US', {
        month: 'short',
        day: 'numeric',
        year: 'numeric',
        timeZone: 'UTC',
    });
}

export function formatRangeLabel(range: DateRange): string {
    if (range.from === range.to) {
        return formatDisplayDate(range.from);
    }
    return `${formatDisplayDate(range.from)} - ${formatDisplayDate(range.to)}`;
}

export function isValidDateRange(range: DateRange): boolean {
    const fromParts = parseDateOnly(range.from);
    const toParts = parseDateOnly(range.to);
    if (!fromParts || !toParts) return false;

    const fromTime = Date.UTC(fromParts.year, fromParts.month, fromParts.day);
    const toTime = Date.UTC(toParts.year, toParts.month, toParts.day);
    return fromTime <= toTime;
}

export function dateStringToDate(dateStr: string): Date {
    const parts = parseDateOnly(dateStr);
    if (!parts) return new Date(dateStr);
    return new Date(Date.UTC(parts.year, parts.month, parts.day));
}

/** Untuk Flatpickr: gunakan kalender lokal agar tidak melenceng dari label WIB */
export function dateStringToPickerDate(dateStr: string): Date {
    const parts = parseDateOnly(dateStr);
    if (!parts) return new Date(dateStr);
    return new Date(parts.year, parts.month, parts.day);
}

export function pickerDateToDateString(date: Date): string {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
}
