package dev.lions.controllers;

import static java.time.LocalDateTime.ofInstant;

import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.event.Event;
import jakarta.faces.application.FacesMessage;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;

import java.io.Serial;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import dev.lions.models.*;
import dev.lions.services.*;
import dev.lions.events.AnalyticsEvent;
import dev.lions.utils.MessageUtils;
import dev.lions.exceptions.BusinessException;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Contrôleur principal de la page d'accueil.
 * Gère l'ensemble des fonctionnalités et données affichées sur la landing page.
 */
@Slf4j
@Named
@RequestScoped
public class HomeController implements Serializable {

  @Serial
  private static final long serialVersionUID = 1L;
  private static final String DEFAULT_FILTER = "all";
  private static final Map<String, Integer> COMPANY_STATS = initializeCompanyStats();

  @Inject
  ProjectService projectService;

  @Inject
  ContactService contactService;

  @Inject
  Event<AnalyticsEvent> analyticsEvent;

  @Getter @Setter
  private String selectedFilter = DEFAULT_FILTER;

  @Getter
  private List<Project> filteredProjects;

  @Getter
  private List<ExpertiseArea> expertiseAreas;

  @Getter
  private List<Service> services;

  @Getter
  private List<ProcessStep> processSteps;

  @Getter
  private String heroTitle = "Accélérez votre transformation digitale";

  @Getter
  private String heroDescription = "Des solutions innovantes pour booster votre croissance";

  /**
   * Initialise le contrôleur et charge les données nécessaires.
   */
  @PostConstruct
  public void init() {
    try {
      log.info("Initialisation du contrôleur Home");

      initializeData();
      updateFilteredProjects();
      fireInitializationEvent();

      log.info("Contrôleur Home initialisé avec succès");

    } catch (Exception e) {
      log.error("Erreur lors de l'initialisation du contrôleur", e);
      MessageUtils.addErrorMessage("Erreur d'initialisation",
                                   "Une erreur est survenue lors du chargement de la page");
    }
  }

  /**
   * Met à jour la liste des projets selon le filtre sélectionné.
   */
  public void updateFilteredProjects() {
    log.debug("Mise à jour des projets avec le filtre: {}", selectedFilter);

    try {
      filteredProjects = projectService.getFilteredProjects(selectedFilter);
      fireFilterUpdateEvent();
    } catch (BusinessException be) {
      log.warn("Erreur lors du filtrage des projets", be);
      MessageUtils.addWarningMessage("Attention", be.getMessage());
    } catch (Exception e) {
      log.error("Erreur critique lors du filtrage", e);
      MessageUtils.addErrorMessage("Erreur",
                                   "Impossible de charger les projets");
      filteredProjects = Collections.emptyList();
    }
  }

  /**
   * Traite la soumission du formulaire de contact.
   *
   * @param form Le formulaire de contact soumis par l'utilisateur
   */
  public void submitContactForm(@Valid @NotNull ContactForm form) {
    log.info("Traitement du formulaire de contact");

    try {
      Contact contact = contactService.processContactForm(form);
      fireContactSubmissionEvent(contact);

      MessageUtils.addSuccessMessage("Message envoyé",
                                     "Votre message a été envoyé avec succès");

    } catch (BusinessException be) {
      log.warn("Erreur de validation du formulaire", be);
      MessageUtils.addWarningMessage("Validation", be.getMessage());
    } catch (Exception e) {
      log.error("Erreur lors du traitement du formulaire", e);
      MessageUtils.addErrorMessage("Erreur",
                                   "Impossible de traiter votre demande");
    }
  }

  /**
   * Initialise les données statiques du contrôleur.
   */
  private void initializeData() {
    expertiseAreas = initializeExpertiseAreas();
    services = initializeServices();
    processSteps = initializeProcessSteps();
  }

  /**
   * Initialise la liste des domaines d'expertise.
   *
   * @return La liste des domaines d'expertise
   */
  private List<ExpertiseArea> initializeExpertiseAreas() {
    log.debug("Initialisation des domaines d'expertise");

    return List.of(
        createExpertiseArea(
            "Développement Sur Mesure",
            "fa-code",
            "Solutions logicielles adaptées à vos besoins",
            List.of(
                "Applications web modernes",
                "Logiciels métier optimisés",
                "APIs performantes"
            )
        ),
        createExpertiseArea(
            "Intégration de Solutions",
            "fa-puzzle-piece",
            "Déploiement et personnalisation",
            List.of(
                "Intégration CRM & ERP",
                "Plateformes e-commerce",
                "Solutions collaboratives"
            )
        )
    );
  }

  /**
   * Crée un nouveau domaine d'expertise.
   *
   * @param title Le titre du domaine
   * @param icon L'icône représentant le domaine
   * @param description La description du domaine
   * @param features Les fonctionnalités et avantages du domaine
   * @return Le nouveau domaine d'expertise créé
   */
  private ExpertiseArea createExpertiseArea(String title, String icon,
                                            String description, List<String> features) {
    return ExpertiseArea.builder()
                        .title(title)
                        .icon(icon)
                        .description(description)
                        .features(features)
                        .priority(1)
                        .build();
  }

  /**
   * Initialise la liste des services proposés.
   *
   * @return La liste des services
   */
  private List<Service> initializeServices() {
    log.debug("Initialisation des services");

    return List.of(
        createService(
            "consulting",
            "Conseil & Stratégie",
            "fa-chart-line",
            "Accompagnement stratégique",
            List.of(
                "Audit technique",
                "Feuille de route digitale",
                "Optimisation des processus"
            )
        ),
        createService(
            "development",
            "Développement",
            "fa-laptop-code",
            "Création de solutions techniques",
            List.of(
                "Développement agile",
                "Intégration continue",
                "Support technique"
            )
        )
    );
  }

  /**
   * Crée un nouveau service.
   *
   * @param id L'identifiant unique du service
   * @param title Le titre du service
   * @param icon L'icône représentant le service
   * @param description La description du service
   * @param benefits Les avantages et bénéfices du service
   * @return Le nouveau service créé
   */
  private Service createService(String id, String title, String icon,
                                String description, List<String> benefits) {
    return Service.builder()
                  .id(id)
                  .title(title)
                  .icon(icon)
                  .description(description)
                  .benefits(benefits)
                  .build();
  }

  /**
   * Initialise la liste des étapes du processus.
   *
   * @return La liste des étapes du processus
   */
  private List<ProcessStep> initializeProcessSteps() {
    log.debug("Initialisation des étapes du processus");

    return List.of(
        createProcessStep(1, "Discovery", "Analyse des besoins", "2-3 semaines"),
        createProcessStep(2, "Conception", "Élaboration de la solution", "3-4 semaines"),
        createProcessStep(3, "Développement", "Création de la solution", "8-12 semaines"),
        createProcessStep(4, "Déploiement", "Mise en production", "2-3 semaines")
    );
  }

  /**
   * Crée une nouvelle étape du processus.
   *
   * @param number Le numéro de l'étape
   * @param title Le titre de l'étape
   * @param description La description de l'étape
   * @param duration La durée estimée de l'étape
   * @return La nouvelle étape créée
   */
  private ProcessStep createProcessStep(int number, String title,
                                        String description, String duration) {
    return ProcessStep.builder()
                      .number(number)
                      .title(title)
                      .description(description)
                      .duration(duration)
                      .build();
  }

  /**
   * Initialise la map des statistiques de l'entreprise.
   *
   * @return La map contenant les statistiques clés
   */
  private static Map<String, Integer> initializeCompanyStats() {
    Map<String, Integer> stats = new ConcurrentHashMap<>();
    stats.put("Projets Réalisés", 150);
    stats.put("Clients Satisfaits", 80);
    stats.put("Experts Techniques", 25);
    return Collections.unmodifiableMap(stats);
  }

  /**
   * Déclenche l'événement d'initialisation de la page d'accueil.
   */
  private void fireInitializationEvent() {
    analyticsEvent.fire(AnalyticsEvent.builder()
                                      .eventType("HOME_INITIALIZED")
                                      .timestamp(ofInstant(Instant.ofEpochMilli(Long.MAX_VALUE),
                                                           ZoneId.systemDefault()))
                                      .build());
  }

  /**
   * Déclenche l'événement de mise à jour du filtre des projets.
   */
  private void fireFilterUpdateEvent() {
    analyticsEvent.fire(AnalyticsEvent.builder()
                                      .eventType("PROJECTS_FILTERED")
                                      .properties(Map.of("filter", selectedFilter))
                                      .build());
  }

  /**
   * Déclenche l'événement de soumission du formulaire de contact.
   *
   * @param contact Le contact créé suite à la soumission du formulaire
   */
  private void fireContactSubmissionEvent(Contact contact) {
    analyticsEvent.fire(AnalyticsEvent.builder()
                                      .eventType("CONTACT_SUBMITTED")
                                      .contactId(contact.getId().toString())
                                      .build());
  }

  /**
   * Retourne le message d'accueil de la page d'accueil.
   *
   * @return Le message d'accueil
   */
  public String getWelcomeMessage() {
    return "Bienvenue chez Lions Dev";
  }

  /**
   * Retourne le sous-titre affiché dans la section héros.
   *
   * @return Le sous-titre de la section héros
   */
  public String getHeroSubtitle() {
    return "Solutions digitales sur mesure";
  }

  /**
   * Retourne la liste des filtres disponibles pour les projets.
   *
   * @return La liste des filtres de projets
   */
  public List<String> getProjectFilters() {
    return List.of("Tous", "Web", "Mobile", "Cloud", "IA");
  }

  /**
   * Retourne les statistiques clés de l'entreprise.
   *
   * @return La map contenant les statistiques de l'entreprise
   */
  public Map<String, Integer> getCompanyStats() {
    return COMPANY_STATS;
  }
}