import { router } from '@inertiajs/react';

/**
 * Route Helper Utilities
 *
 * A collection of utility functions for route handling in Inertia.js applications.
 */

// Define the Ziggy route function type
interface ZiggyRoute {
    (name: string, params?: any): string;
    current(name?: undefined): string;
    current(name: string): boolean;
}

// Store reference to the original Ziggy route function
// This is set by bootstrap or app.tsx before window.route is overwritten
let ziggyRoute: ZiggyRoute | null = null;

/**
 * Set the original Ziggy route function
 * Call this before overwriting window.route
 */
export function setZiggyRoute(originalRoute: ZiggyRoute): void {
    ziggyRoute = originalRoute;
}

/**
 * Get the Ziggy route function
 */
function getZiggyRoute(): ZiggyRoute | null {
    if (ziggyRoute) return ziggyRoute;

    // Fallback: try to get from window if it hasn't been overwritten yet
    if (typeof window !== 'undefined' && typeof window.route === 'function') {
        const winRoute = window.route as ZiggyRoute;
        // Make sure it's the real Ziggy route (has .current method)
        if ('current' in winRoute) {
            ziggyRoute = winRoute;
            return ziggyRoute;
        }
    }
    return null;
}

/**
 * Get the current route name from the page props
 */
export function currentRoute(): string | undefined {
    const zRoute = getZiggyRoute();
    if (zRoute) {
        return zRoute.current();
    }
    return (document as any).querySelector('meta[name="route-name"]')?.content;
}

/**
 * Check if the current route matches the given route name
 */
export function isRoute(name: string): boolean {
    const zRoute = getZiggyRoute();
    if (zRoute) {
        return zRoute.current(name);
    }
    return currentRoute() === name;
}

/**
 * Check if the current route matches any of the given route names
 */
export function isAnyRoute(names: string[]): boolean {
    return names.some((name) => isRoute(name));
}

/**
 * Known route patterns for fallback URL generation
 */
const ROUTE_PATTERNS: Record<string, string> = {
    'news.show': '/news/{slug}',
    'api.news.show': '/api/news/{slug}',
    'api.news.popup.active': '/api/news/popup/active',
    home: '/',
    dashboard: '/dashboard',
    'dashboard.log': '/dashboard/history',
    'dashboard.online': '/dashboard/online',
    'dashboard.online.show': '/dashboard/online/{roleId}',
    'dashboard.voucher.index': '/dashboard/voucher',
    'dashboard.voucher.check': '/dashboard/voucher/check',
    'dashboard.voucher.redeem': '/dashboard/voucher/redeem',
    login: '/login',
    register: '/register',
    'admin.topup.ipaymu.settings.update': '/admin/topup/ipaymu/settings',
    'admin.topup.duitku.settings.update': '/admin/topup/duitku/settings',
    'admin.topup.tripay.settings.update': '/admin/topup/tripay/settings',
    'admin.topup.pakasir.settings.update': '/admin/topup/pakasir/settings',
    'admin.topup.ipaymu.sync-transaction': '/admin/topup/ipaymu/sync-transaction/{id}',
    'admin.topup.duitku.sync-transaction': '/admin/topup/duitku/sync-transaction/{id}',
    'admin.topup.tripay.sync-transaction': '/admin/topup/tripay/sync-transaction/{id}',
    'admin.topup.pakasir.sync-transaction': '/admin/topup/pakasir/sync-transaction/{id}',
    'admin.topup.ipaymu.check-transaction': '/admin/topup/ipaymu/check-transaction',
    'admin.topup.duitku.check-transaction': '/admin/topup/duitku/check-transaction',
    'admin.topup.pakasir.check-transaction': '/admin/topup/pakasir/check-transaction',
};

/**
 * Build URL manually from route pattern and params
 */
function buildFallbackUrl(name: string, params?: Record<string, string | number> | string | number): string {
    const pattern = ROUTE_PATTERNS[name];
    if (!pattern) {
        console.warn(`No fallback route pattern for: ${name}`);
        return '#';
    }

    if (!params || typeof params !== 'object') {
        return pattern.replace(/\{[^}]+\}/g, String(params ?? ''));
    }

    let url = pattern;
    for (const [key, value] of Object.entries(params)) {
        url = url.replace(`{${key}}`, String(value));
    }
    return url;
}

/**
 * Generate a URL for a named route using original Ziggy
 */
export function routeUrl(name: string, params?: Record<string, string | number> | string | number): string {
    const zRoute = getZiggyRoute();
    if (zRoute) {
        try {
            const url = zRoute(name, params);
            if (url !== '#' && !url.includes('{')) {
                return url;
            }
        } catch {
            // Fall through to manual fallback
        }
    }
    return buildFallbackUrl(name, params);
}

/**
 * Navigate to a route using Inertia
 */
export function navigateTo(
    name: string,
    params?: Record<string, string | number> | string | number,
    options?: {
        replace?: boolean;
        preserveState?: boolean;
        preserveScroll?: boolean;
        only?: string[];
    },
): void {
    const url = routeUrl(name, params);
    router.visit(url, {
        method: 'get',
        replace: options?.replace ?? false,
        preserveState: options?.preserveState ?? false,
        preserveScroll: options?.preserveScroll ?? false,
        only: options?.only,
    });
}

/**
 * Reload the current page
 */
export function reloadPage(options?: { preserveState?: boolean; preserveScroll?: boolean; only?: string[] }): void {
    router.reload({
        preserveState: options?.preserveState ?? false,
        preserveScroll: options?.preserveScroll ?? false,
        only: options?.only,
    });
}

/**
 * Go back to the previous page
 */
export function goBack(fallback?: string): void {
    if (window.history.length > 1) {
        window.history.back();
    } else if (fallback) {
        router.visit(fallback);
    }
}

/**
 * Check if the user is on an auth-related route
 */
export function isAuthRoute(): boolean {
    const authRoutes = [
        'login',
        'register',
        'password.request',
        'password.reset',
        'password.setup.auth',
        'verification.notice',
        'verification.verify',
        'activation.pending',
        'activation.verify',
    ];
    return authRoutes.some((route) => isRoute(route));
}

/**
 * Check if the user is on a public route (no authentication required)
 */
export function isPublicRoute(): boolean {
    const publicRoutes = [
        'home',
        'login',
        'register',
        'password.request',
        'password.reset',
        'password.setup.auth',
        'news.index',
        'news.show',
        'download',
        'ranking.player',
        'ranking.pvp',
        'auth.google',
        'auth.google.callback',
    ];
    return publicRoutes.some((route) => isRoute(route)) || window.location.pathname === '/';
}

/**
 * Check if the user is on an admin route
 */
export function isAdminRoute(): boolean {
    return window.location.pathname.startsWith('/admin') || isRoute('admin.dashboard');
}

/**
 * Get route parameters from the current URL
 */
export function getRouteParams(): Record<string, string> {
    const params: Record<string, string> = {};
    const urlParams = new URLSearchParams(window.location.search);

    urlParams.forEach((value, key) => {
        params[key] = value;
    });

    return params;
}

/**
 * Get a specific route parameter
 */
export function getRouteParam(key: string, defaultValue: string = ''): string {
    const urlParams = new URLSearchParams(window.location.search);
    return urlParams.get(key) || defaultValue;
}

/**
 * Build a query string from an object
 */
export function buildQueryString(params: Record<string, string | number | boolean | undefined>): string {
    const query = Object.entries(params)
        .filter(([, value]) => value !== undefined && value !== null && value !== '')
        .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
        .join('&');

    return query ? `?${query}` : '';
}

/**
 * Parse a query string into an object
 */
export function parseQueryString(queryString: string = window.location.search): Record<string, string> {
    const params: Record<string, string> = {};
    const urlParams = new URLSearchParams(queryString);

    urlParams.forEach((value, key) => {
        params[key] = value;
    });

    return params;
}

/**
 * Navigate with query parameters
 */
export function navigateWithQuery(
    name: string,
    params?: Record<string, string | number>,
    query?: Record<string, string | number | boolean>,
    options?: {
        replace?: boolean;
        preserveState?: boolean;
        preserveScroll?: boolean;
    },
): void {
    let url = routeUrl(name, params);

    if (query && Object.keys(query).length > 0) {
        url += buildQueryString(query);
    }

    router.visit(url, {
        method: 'get',
        replace: options?.replace ?? false,
        preserveState: options?.preserveState ?? false,
        preserveScroll: options?.preserveScroll ?? false,
    });
}

/**
 * Redirect to login page with intended URL
 */
export function redirectToLogin(): void {
    router.visit(routeUrl('login'), {
        method: 'get',
    });
}

/**
 * Redirect to dashboard based on user role
 */
export function redirectToDashboard(role: string = 'player'): void {
    if (role === 'admin') {
        router.visit('/admin/dashboard');
    } else {
        router.visit(routeUrl('dashboard'));
    }
}

// Alias for routeUrl - commonly used as 'route'
export const route = routeUrl;

export default {
    current: currentRoute,
    is: isRoute,
    isAny: isAnyRoute,
    url: routeUrl,
    route: routeUrl,
    navigate: navigateTo,
    reload: reloadPage,
    back: goBack,
    isAuth: isAuthRoute,
    isPublic: isPublicRoute,
    isAdmin: isAdminRoute,
    getParams: getRouteParams,
    getParam: getRouteParam,
    buildQuery: buildQueryString,
    parseQuery: parseQueryString,
    navigateWithQuery,
    redirectToLogin,
    redirectToDashboard,
};
