use std::collections::HashSet;

use dioxus::prelude::*;

use crate::togglable::Togglable;
use crate::page::Page;
use crate::server::*;
use crate::settings::{BardSettings};
use super::tags::*;



#[component]
pub fn BlogItem(title: String, slug: String, author: String, summary: String,
                tags: Vec<String>)
                -> Element
{
   let author_future = use_server_future(move ||
   {
      let handle: String = author.clone();

      async move { get_author(handle).await }
   })?;

   rsx!
   {
      article
      {
         class: "blog_item",

         h2
         {
            Link
            {
               to: Page::Post { slug: slug.clone() },

               "{title}"
            }
         }

         TagList
         {
            for tag in tags
            {
               TagItem
               {
                  tag: tag.clone(),
               }
            }
         }

         if let Some(Ok(Some(adventurer))) = (author_future.value())()
         {
            p
            {
               b
               {
                  "Author: "
                  a
                  {
                     href: "{adventurer.legend.profile}", "{adventurer.name}"
                  }
               }
            }
         }
         else
         {
            p { "Loading author..." }
         }

         p { "{summary}" }
      }
   }
}


#[component]
pub fn BlogList(tags: Signal<HashSet<String>>, children: Element) -> Element
{
   // Retrieve the provided settings from context.
   let settings = use_context::<BardSettings>();

   let list = use_resource(move ||
   {
      let tags = tags();
      let categories: Vec<String> = tags.iter().cloned().collect();

      async move { get_blog_list(categories).await }
   });

   rsx!
   {
      section
      {
         class: "blog_list",

         match settings.blog_image
         {
            Some(image) =>
            {
               match settings.blog_name
               {
                  Some(title) =>
                  {
                     rsx!
                     {
                        h1 { class: "blog_title visually_hidden", "{title}" }
                        img { class: "blog_title_image", alt: "{title} blog logo", src: image }
                     }
                  }

                  None =>
                  {
                     rsx!
                     {
                        h1 { class: "blog_title visually_hidden", "Blog" }
                        img { class: "blog_title_image", alt: "Blog logo", src: image }
                     }
                  }
               }
            }

            None =>
            {
               match settings.blog_name
               {
                  Some(title) =>
                  {
                     rsx!
                     {
                        h1 { class: "blog_title", "{title}" }
                     }
                  }

                  None =>
                  {
                     rsx!
                     {
                        h1 { class: "blog_title visually_hidden", "Blog" }
                     }
                  }
               }
            }
         }

         if let Some(Ok(lores)) = &*list.read()
         {
            for lore in lores
            {
               BlogItem
               {
                  key: "{lore.slug}",
                  title: lore.title.clone(),
                  slug: lore.slug.clone(),
                  author: lore.author.clone(),
                  summary: lore.summary.clone(),
                  tags: lore.tags.clone()
               }
            }
         }
         else if let Some(Err(_e)) = &*list.read()
         {
            p { "Please choose a category to see related blog posts." }
         }
         else
         {
            p { "Loading..." }
         }

         {children}
      }
   }
}


#[component]
pub fn ToggleTag(tag: String, toggled_tags: Signal<HashSet<String>>) -> Element
{
   let is_checked = toggled_tags.read().is_toggled(&tag);
   rsx!
   {
      label
      {
         class: "toggle_button",

         input
         {
            r#type: "checkbox",
            checked: is_checked,
            onchange: move |_|
                      {
                         toggled_tags.write().toggle(&tag.clone());
                      },
         }

         "{tag}"
      }
   }
}


// Using use_resource instead of use_server_future for URL-dependent tag selection
//
// While use_server_future should theoretically be reactive when reading signals in the
// closure (per Dioxus docs), in practice it doesn't reliably re-run when the url_tag
// signal changes, especially during direct URL navigation (typing URLs in browser).
//
// use_resource provides more reliable reactivity for this use case because:
// 1. It explicitly depends on url_tag and consistently re-runs when it changes
// 2. It handles both async data fetching AND selection logic in a single atomic operation
// 3. It works consistently across all navigation methods (links, direct URLs, etc.)
// 4. It avoids timing coordination issues between separate hooks
//
// This approach combines fetching available tags from the server with determining
// which tags should be selected based on the current URL, returning both pieces
// of data together for clean state management.
#[component]
pub fn TagSelector(url_tag: ReadSignal<String>,
                   toggled_tags: Signal<HashSet<String>>) -> Element
{
   // Use use_resource to handle both fetching tags AND initializing selection
   let tags_and_selection = use_resource(move ||
   {
      let current_url = url_tag();

      async move
      {
         match get_tags().await
         {
            Ok(available_tags) =>
            {
               // Determine what should be selected based on URL
               let should_show_all = current_url.is_empty() || current_url == "all";

               let selected_tags: HashSet<String> = if should_show_all
               {
                  available_tags.iter().cloned().collect()
               }
               else
               {
                  let url_categories = convert_categories(&current_url);

                  let filtered: HashSet<String> = url_categories.into_iter()
                     .filter(|tag| available_tags.contains(tag))
                     .collect();

                  filtered
               };

               Ok((available_tags, selected_tags))
            }

            Err(e) =>
            {
               eprintln!("RESOURCE - Error: {}", e);
               Err(e)
            }
         }
      }
   });

   // Separate effect to update toggled_tags when resource completes
   // This separates reading the resource from writing to toggled_tags
   use_effect(move ||
   {
      if let Some(Ok((_, selected_tags))) = &*tags_and_selection.read()
      {
         toggled_tags.set(selected_tags.clone());
      }
   });


   rsx!
   {
      section
      {
         class: "blog_nav",

         h2 { class: "visually_hidden", "Filters and Navigation" }

         fieldset
         {
            class: "tag_style",

            legend { "Category Filter" }

            ul
            {
               class: "tag_list",

               match &*tags_and_selection.read()
               {
                  Some(Ok((available_tags, _))) =>
                  {
                     rsx!
                     {
                        for tag in available_tags
                        {
                           li
                           {
                              key: "selector-{tag}",
                              class: "tag_item",

                              ToggleTag
                              {
                                 tag: tag.clone(),
                                 toggled_tags: toggled_tags
                              }
                           }
                        }
                     }
                  }

                  Some(Err(_)) =>
                  {
                     rsx!
                     {
                        li { "Error loading tags" }
                     }
                  }

                  None =>
                  {
                     rsx!
                     {
                        li { "Loading tags..." }
                     }
                  }
               }
            }
         }
      }
   }
}

fn convert_categories(categories: &str) -> HashSet<String>
{
   categories
      .split('+')
      .filter(|s| !s.is_empty() && *s != "all")
      .map(str::to_string)
      .collect()
}
