import { type Ref, type ComputedRef, computed, defineComponent, inject, ref, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';

import { useVuelidate } from '@vuelidate/core';
import { required } from '@vuelidate/validators';

import StrutturaService from '@/entities/struttura/struttura.service';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import LiberatoriaService from '@/entities/liberatoria/liberatoria.service';
import ModelloLiberatoriaService from '@/entities/modello-liberatoria/modello-liberatoria.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IPrenotazione, Prenotazione } from '@/shared/model/prenotazione.model';
import { type IStruttura } from '@/shared/model/struttura.model';
import { type IUtenteApp } from '@/shared/model/utente-app.model';
import { type ILiberatoria, Liberatoria } from '@/shared/model/liberatoria.model';
import { type IModelloLiberatoria } from '@/shared/model/modello-liberatoria.model';
import { StatoPrenotazione } from '@/shared/model/enumerations/stato-prenotazione.model';

import PrenotazioneService from './prenotazione.service';

export default defineComponent({
  name: 'PrenotazioneFormUser',
  setup() {
    const authenticated = inject<ComputedRef<boolean>>('authenticated');

    const prenotazioneService = inject('prenotazioneService', () => new PrenotazioneService());
    const alertService = inject('alertService', () => useAlertService(), true);

    const prenotazione: Ref<IPrenotazione> = ref(new Prenotazione());

    const utenteAppService = inject('utenteAppService', () => new UtenteAppService());
    const currentUser: Ref<IUtenteApp | null> = ref(null);
    const userType: Ref<'privato' | 'societa'> = ref('privato');

    const strutturaService = inject('strutturaService', () => new StrutturaService());
    const strutturas: Ref<IStruttura[]> = ref([]);

    const liberatoriaService = inject('liberatoriaService', () => new LiberatoriaService());
    const modelloLiberatoriaService = inject('modelloLiberatoriaService', () => new ModelloLiberatoriaService());

    // Liberatorie state
    const modelloLiberatorias: Ref<IModelloLiberatoria[]> = ref([]);
    const userLiberatorias: Ref<ILiberatoria[]> = ref([]);
    const isLoadingLiberatorie = ref(false);
    const selectedModello: Ref<IModelloLiberatoria | null> = ref(null);

    const isSaving = ref(false);
    const isLoading = ref(true);
    const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);

    const router = useRouter();

    const { t: t$ } = useI18n();

    // Initialize prenotazione with RICHIESTA status
    prenotazione.value.stato = 'RICHIESTA';

    const validationRules = {
      oraInizio: {},
      oraFine: {},
      stato: {},
      motivoEvento: {},
      numeroPartecipanti: {},
      noteUtente: {},
      struttura: { required },
    };
    const v$ = useVuelidate(validationRules, prenotazione as any);

    // Computed properties for liberatorie
    const liberatorieStatus = computed(() => {
      if (!prenotazione.value.struttura?.id) return [];

      // Filter ModelloLiberatoria for selected struttura
      const strutturaModelli = modelloLiberatorias.value.filter(m => m.struttura?.id === prenotazione.value.struttura.id);

      // Map to include acceptance status
      return strutturaModelli.map(modello => {
        const accepted = userLiberatorias.value.find(lib => lib.modelloLiberatoria?.id === modello.id);
        return {
          modello,
          liberatoria: accepted || null,
          isAccepted: !!accepted,
        };
      });
    });

    const allLiberatorieAccepted = computed(() => {
      const status = liberatorieStatus.value;
      return status.length === 0 || status.every(s => s.isAccepted);
    });

    const loadLiberatorieData = async () => {
      if (!currentUser.value?.id) return;

      try {
        isLoadingLiberatorie.value = true;

        // Fetch all ModelloLiberatoria (filter client-side)
        const modelliRes = await modelloLiberatoriaService().retrieve();
        modelloLiberatorias.value = modelliRes.data;

        // Fetch all Liberatoria and filter by current user
        const liberatorieRes = await liberatoriaService().retrieve();
        userLiberatorias.value = liberatorieRes.data.filter((lib: ILiberatoria) => lib.utente?.id === currentUser.value.id);

        isLoadingLiberatorie.value = false;
      } catch (error) {
        isLoadingLiberatorie.value = false;
        alertService.showHttpError(error.response);
      }
    };

    const initData = async () => {
      try {
        isLoading.value = true;

        // Fetch current user
        const userData = await utenteAppService().getCurrentUser();
        currentUser.value = userData;
        prenotazione.value.utente = userData;

        // Fetch struttura list
        const res = await strutturaService().retrieve();
        strutturas.value = res.data;

        // Load liberatorie data
        await loadLiberatorieData();

        isLoading.value = false;
      } catch (error) {
        isLoading.value = false;
        alertService.showHttpError(error.response);
      }
    };

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

    const resetForm = () => {
      prenotazione.value = new Prenotazione();
      prenotazione.value.stato = 'RICHIESTA';
      prenotazione.value.utente = currentUser.value;
      v$.value.$reset();
    };

    return {
      authenticated,
      prenotazioneService,
      alertService,
      prenotazione,
      currentUser,
      userType,
      strutturas,
      isSaving,
      isLoading,
      currentLanguage,
      v$,
      resetForm,
      // Liberatorie additions
      liberatoriaService,
      modelloLiberatoriaService,
      modelloLiberatorias,
      userLiberatorias,
      isLoadingLiberatorie,
      selectedModello,
      liberatorieStatus,
      allLiberatorieAccepted,
      ...useDateFormat({ entityRef: prenotazione }),
      t$,
    };
  },
  methods: {
    save(): void {
      this.isSaving = true;
      this.v$.$validate();

      if (this.v$.$invalid) {
        this.isSaving = false;
        return;
      }

      // Check if all required liberatorie are accepted
      if (!this.allLiberatorieAccepted) {
        this.isSaving = false;
        this.alertService.showError(this.t$('smartbookingApp.prenotazione.userForm.liberatorieRequired').toString());
        return;
      }

      this.prenotazioneService()
        .create(this.prenotazione)
        .then(param => {
          this.isSaving = false;
          this.alertService.showSuccess(this.t$('smartbookingApp.prenotazione.created', { param: param.id }).toString());
          this.$router.push({ name: 'Prenotazione' });
        })
        .catch(error => {
          this.isSaving = false;
          this.alertService.showHttpError(error.response);
        });
    },

    showLiberatoriaModal(modello: IModelloLiberatoria): void {
      this.selectedModello = modello;
      (<any>this.$refs.liberatoriaModal).show();
    },

    closeLiberatoriaModal(): void {
      this.selectedModello = null;
      (<any>this.$refs.liberatoriaModal).hide();
    },

    async acceptLiberatoria(): Promise<void> {
      if (!this.selectedModello || !this.currentUser) return;

      try {
        this.isSaving = true;

        // Create new Liberatoria
        const newLiberatoria = new Liberatoria();
        newLiberatoria.accettata = new Date();
        newLiberatoria.utente = this.currentUser;
        newLiberatoria.modelloLiberatoria = this.selectedModello;

        const result = await this.liberatoriaService().create(newLiberatoria);

        // Add to local state
        this.userLiberatorias.push(result);

        // Close modal
        this.closeLiberatoriaModal();

        // Show success message
        this.alertService.showSuccess(this.t$('smartbookingApp.liberatoria.created', { param: result.id }).toString());

        this.isSaving = false;
      } catch (error) {
        this.isSaving = false;
        this.alertService.showHttpError(error.response);
      }
    },
  },
});
