import { createApp, ref, onMounted } from 'vue';
import { useGuards } from './composables/useGuards';
import { createPinia } from 'pinia';
import { useUiStore } from './stores/ui';
import { useAuthStore } from './stores/auth';
import { useCrudStore } from './stores/crud';
import { useNotificationStore } from './stores/notification';
import { useQueueStore } from './stores/queue';
import route from './general/functions/router';
import Vapor from 'laravel-vapor';
import { debounce } from 'vue-debounce';
import emitter from './utils/emitter';
import VMoney, { Money3Directive } from 'v-money3'
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';


window.route = route;
window.Vapor = Vapor;
window.Vapor.withBaseAssetUrl(import.meta.env.VITE_VAPOR_ASSET_URL);

window.Pusher = Pusher;
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
    forceTLS: true
});

// Pinia must be created and installed before any store is used
const pinia = createPinia();
const app = createApp({
    setup() {
        const captchaId = ref<number | null>(null);
        const reCaptchaToken = ref<string | null>(null);
        const authStore = useAuthStore();
        const crudStore = useCrudStore();
        const { routesGuard, isProtectedRoute, isWithTokenRoute } = useGuards();

        //Route Guard
        routesGuard();

        //Google reCAPTCHA
        const updateCaptchaToken = () => {
            // console.log('updateCaptchaToken called', {
            //     grecaptchaExists: !!window.grecaptcha,
            //     captchaId: captchaId.value,
            //     storeToken: authStore.getReCaptcha,
            //     localToken: reCaptchaToken.value
            // });
            if (window.grecaptcha && captchaId.value != null && authStore.getReCaptcha === reCaptchaToken.value) {
                // console.log('Executing grecaptcha.execute with ID:', captchaId.value);
                window.grecaptcha.execute(captchaId.value).then((token: string) => {
                    // console.log('grecaptcha.execute resolved. Token:', token);
                    reCaptchaToken.value = token;
                    authStore.reCaptcha({ token });
                }).catch((err: any) => {
                    // console.error('grecaptcha.execute error:', err);
                });
            }
        };

        const execute = debounce(() => {
            // console.log('execute (debounced) called');
            updateCaptchaToken();
        }, 3000);

        (window as any).executeRecaptcha = execute;

        const render = () => {
            // console.log('render called');
            if (window.grecaptcha) {
                let container = document.getElementById('grecaptcha_container');
                if (!container) {
                    // console.log('grecaptcha_container not found, creating dynamically');
                    container = document.createElement('div');
                    container.setAttribute('id', 'grecaptcha_container');
                    document.body.appendChild(container);
                }
                captchaId.value = window.grecaptcha.render('grecaptcha_container', {
                    sitekey: '6Lft5mkhAAAAAAFgQ0gWlwte1h-o6UPRpMNHP1xz',
                    badge: '',
                    size: 'invisible',
                    'expired-callback': execute
                });
                // console.log('grecaptcha.render completed. captchaId:', captchaId.value);
                execute();
            }
        };

        const init = () => {
            if (!document.getElementById('gRecaptchaScript')) {
                window.gRecaptchaOnLoadCallbacks = [render];
                window.gRecaptchaOnLoad = function () {
                    for (let i = 0; i < window.gRecaptchaOnLoadCallbacks.length; i++) {
                        window.gRecaptchaOnLoadCallbacks[i]();
                    }
                    delete (window as any).gRecaptchaOnLoadCallbacks;
                    delete (window as any).gRecaptchaOnLoad;
                };

                let recaptchaScript = document.createElement('script');
                recaptchaScript.setAttribute('src', 'https://www.google.com/recaptcha/api.js?render=explicit&onload=gRecaptchaOnLoad');
                recaptchaScript.setAttribute('id', 'gRecaptchaScript');
                recaptchaScript.async = true;
                recaptchaScript.defer = true;
                document.head.appendChild(recaptchaScript);
            } else if (!window.grecaptcha || !window.grecaptcha.render) {
                if (!window.gRecaptchaOnLoadCallbacks) window.gRecaptchaOnLoadCallbacks = [];
                window.gRecaptchaOnLoadCallbacks.push(render);
            } else {
                render();
            }
        };

        onMounted(() => {
            init();
        });

        //If a normal user opens a protected page and doesn’t already have a special token-based route,
        //asks the backend for a fresh access token and updates the session without user interaction.
        if (
            !authStore.isAdmin &&
            !('company_marking' in authStore.getDecodedAccessToken.user) &&
            isProtectedRoute() &&
            !isWithTokenRoute()
        ) {
            crudStore.crudRequest({
                endpoint: route('api.account.authentication.refresh'),
                method: 'get'
            }).then(async (response: Response) => {
                if (response.ok) {
                    const data = await response.json();
                    authStore.userAuthentication({
                        access_token: data.payload.refresh_token,
                        redirect_url: window.location.href
                    });
                }
            });
        }
    }
});

// Pinia store
app.use(pinia);

// V-Money
app.use(VMoney);
// app.directive('money', Money3Directive);

// Expose stores for legacy Blade templates that are not SFCs
(app.config.globalProperties as any).authStore = useAuthStore();
(app.config.globalProperties as any).uiStore = useUiStore();

app.config.globalProperties.route = window.route;
app.config.globalProperties.asset = window.Vapor.asset;
app.config.globalProperties.emitter = emitter;

// Auto-register components (eager loaded)
const modules = import.meta.glob('./**/*.vue', { eager: true });
Object.entries(modules).forEach(([path, module]) => {
    const componentName = path.split('/').pop()?.split('.')[0];
    if (componentName) {
        app.component(componentName, (module as any).default);
    }
});

app.directive('tooltip', {
    mounted(el, binding) {
        if (window.$) {
            window.$(el).tooltip({
                title: binding.value,
                placement: binding.arg || 'top',
                trigger: 'hover'
            });
        }
    }
});


app.mount('#app');
