use leptos::prelude::*;
use leptos::task::spawn_local;
use std::collections::HashSet;
use icons::{ArrowUpDown, Inbox, Settings2, Play, Square, Trash2, Ellipsis};
use crate::store::{get_action_messages, show_toast};
use crate::api;
use shared::NotificationLevel;
use crate::components::context_menu::TorrentContextMenu;
use crate::components::ui::card::{Card, CardHeader, CardTitle, CardContent as CardBody};
use crate::components::ui::data_table::*;
use crate::components::ui::checkbox::Checkbox;
use crate::components::ui::button::{Button, ButtonVariant, ButtonSize};
use crate::components::ui::empty::*;
use crate::components::ui::input::Input;
use crate::components::ui::multi_select::*;
use crate::components::ui::dropdown_menu::*;
use crate::components::ui::alert_dialog::*;

const ALL_COLUMNS: [(&str, &str); 8] = [
    ("Name", "Name"),
    ("Size", "Size"),
    ("Progress", "Progress"),
    ("Status", "Status"),
    ("DownSpeed", "DL Speed"),
    ("UpSpeed", "UP Speed"),
    ("ETA", "ETA"),
    ("AddedDate", "Date"),
];

fn format_bytes(bytes: i64) -> String {
    const UNITS: [&str; 6] = ["B", "KB", "MB", "GB", "TB", "PB"];
    if bytes < 1024 { return format!("{} B", bytes); }
    let i = (bytes as f64).log2().div_euclid(10.0) as usize;
    format!("{:.1} {}", (bytes as f64) / 1024_f64.powi(i as i32), UNITS[i])
}

fn format_speed(bytes_per_sec: i64) -> String {
    if bytes_per_sec == 0 { return "0 B/s".to_string(); }
    format!("{}/s", format_bytes(bytes_per_sec))
}

fn format_duration(seconds: i64) -> String {
    if seconds <= 0 { return "∞".to_string(); }
    let days = seconds / 86400;
    let hours = (seconds % 86400) / 3600;
    let minutes = (seconds % 3600) / 60;
    let secs = seconds % 60;
    if days > 0 { format!("{}d {}h", days, hours) }
    else if hours > 0 { format!("{}h {}m", hours, minutes) }
    else if minutes > 0 { format!("{}m {}s", minutes, secs) }
    else { format!("{}s", secs) }
}

fn format_date(timestamp: i64) -> String {
    if timestamp <= 0 { return "N/A".to_string(); }
    let dt = chrono::DateTime::from_timestamp(timestamp, 0);
    match dt { Some(dt) => dt.format("%d/%m/%Y %H:%M").to_string(), None => "N/A".to_string() }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum SortColumn {
    Name, Size, Progress, Status, DownSpeed, UpSpeed, ETA, AddedDate,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum SortDirection { Ascending, Descending }

#[component]
pub fn TorrentTable() -> impl IntoView {
    let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
    let sort_col = signal(SortColumn::AddedDate);
    let sort_dir = signal(SortDirection::Descending);
    
    let selected_hashes = RwSignal::new(HashSet::<String>::new());
    
    let visible_columns = RwSignal::new(HashSet::from([
        "Name".to_string(), "Size".to_string(), "Progress".to_string(), 
        "Status".to_string(), "DownSpeed".to_string(), "UpSpeed".to_string(),
        "ETA".to_string(), "AddedDate".to_string()
    ]));

    let sorted_hashes_data = Memo::new(move |_| {
        let torrents_map = store.torrents.get();
        let filter = store.filter.get();
        let search = store.search_query.get();
        let search_lower = search.to_lowercase();
        
        let mut torrents: Vec<shared::Torrent> = torrents_map.values().filter(|t| {
            let matches_filter = match filter {
                crate::store::FilterStatus::All => true,
                crate::store::FilterStatus::Downloading => t.status == shared::TorrentStatus::Downloading,
                crate::store::FilterStatus::Seeding => t.status == shared::TorrentStatus::Seeding,
                crate::store::FilterStatus::Completed => t.status == shared::TorrentStatus::Seeding || (t.status == shared::TorrentStatus::Paused && t.percent_complete >= 100.0),
                crate::store::FilterStatus::Paused => t.status == shared::TorrentStatus::Paused,
                crate::store::FilterStatus::Inactive => t.status == shared::TorrentStatus::Paused || t.status == shared::TorrentStatus::Error,
                _ => true,
            };
            let matches_search = if search_lower.is_empty() { true } else { t.name.to_lowercase().contains(&search_lower) };
            matches_filter && matches_search
        }).cloned().collect();

        torrents.sort_by(|a, b| {
            let col = sort_col.0.get();
            let dir = sort_dir.0.get();
            let cmp = match col {
                SortColumn::Name => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
                SortColumn::Size => a.size.cmp(&b.size),
                SortColumn::Progress => a.percent_complete.partial_cmp(&b.percent_complete).unwrap_or(std::cmp::Ordering::Equal),
                SortColumn::Status => format!("{:?}", a.status).cmp(&format!("{:?}", b.status)),
                SortColumn::DownSpeed => a.down_rate.cmp(&b.down_rate),
                SortColumn::UpSpeed => a.up_rate.cmp(&b.up_rate),
                SortColumn::ETA => {
                    let a_eta = if a.eta <= 0 { i64::MAX } else { a.eta };
                    let b_eta = if b.eta <= 0 { i64::MAX } else { b.eta };
                    a_eta.cmp(&b_eta)
                }
                SortColumn::AddedDate => a.added_date.cmp(&b.added_date),
            };
            if dir == SortDirection::Descending { cmp.reverse() } else { cmp }
        });
        torrents
    });

    let filtered_hashes = Memo::new(move |_| {
        sorted_hashes_data.get().into_iter().map(|t| t.hash.clone()).collect::<Vec<String>>()
    });

    let selected_count = Signal::derive(move || {
        let current_hashes: HashSet<String> = filtered_hashes.get().into_iter().collect();
        selected_hashes.with(|selected| {
            selected.iter().filter(|h| current_hashes.contains(*h)).count()
        })
    });

    let has_selection = Signal::derive(move || selected_count.get() > 0);

    let handle_select_all = Callback::new(move |checked: bool| {
        selected_hashes.update(|selected| {
            let hashes = filtered_hashes.get_untracked();
            for h in hashes {
                if checked { selected.insert(h); } 
                else { selected.remove(&h); }
            }
        });
    });

    let handle_sort = move |col: SortColumn| {
        if sort_col.0.get() == col {
            sort_dir.1.update(|d| {
                *d = match d { SortDirection::Ascending => SortDirection::Descending, SortDirection::Descending => SortDirection::Ascending };
            });
        } else {
            sort_col.1.set(col);
            sort_dir.1.set(SortDirection::Ascending);
        }
    };

    let sort_icon = move |col: SortColumn| {
        let is_active = sort_col.0.get() == col;
        let class = if is_active { "size-3 text-primary" } else { "size-3 opacity-30 group-hover:opacity-100 transition-opacity" };
        view! { <ArrowUpDown class=class.to_string() /> }.into_any()
    };

    let bulk_action = move |action: &'static str| {
        let hashes: Vec<String> = selected_hashes.get().into_iter().collect();
        if hashes.is_empty() { return; }
        
        spawn_local(async move {
            let mut success = true;
            for hash in hashes {
                let res = match action {
                    "start" => api::torrent::start(&hash).await,
                    "stop" => api::torrent::stop(&hash).await,
                    "delete" => api::torrent::delete(&hash).await,
                    "delete_with_data" => api::torrent::delete_with_data(&hash).await,
                    _ => Ok(()),
                };
                if res.is_err() { success = false; }
            }
            if success {
                show_toast(NotificationLevel::Success, format!("Toplu işlem başarıyla tamamlandı: {}", action));
                selected_hashes.update(|s| s.clear());
            } else {
                show_toast(NotificationLevel::Error, "Bazı işlemler başarısız oldu.");
            }
        });
    };

    let on_action = Callback::new(move |(action, hash): (String, String)| {
        let (success_msg_str, error_msg_str): (&'static str, &'static str) = get_action_messages(&action);
        let success_msg = success_msg_str.to_string();
        let error_msg = error_msg_str.to_string();
        spawn_local(async move {
            let result = match action.as_str() {
                "delete" => api::torrent::delete(&hash).await,
                "delete_with_data" => api::torrent::delete_with_data(&hash).await,
                "start" => api::torrent::start(&hash).await,
                "stop" => api::torrent::stop(&hash).await,
                _ => api::torrent::action(&hash, &action).await,
            };
            match result {
                Ok(_) => show_toast(NotificationLevel::Success, success_msg),
                Err(e) => show_toast(NotificationLevel::Error, format!("{}: {:?}", error_msg, e)),
            }
        });
    });

    view! {
        <div class="h-full bg-background relative flex flex-col overflow-hidden px-4 py-4 gap-4">
            // --- TOPBAR ---
            <div class="flex items-center justify-between gap-4">
                <div class="flex items-center gap-2 flex-1 max-w-md">
                    <Input
                        class="h-9"
                        placeholder="Torrent ara..."
                        bind_value=store.search_query
                    />
                </div>

                <div class="flex items-center gap-2">
                    <Show when=move || has_selection.get()>
                        <DropdownMenu>
                            <DropdownMenuTrigger class="gap-2 bg-secondary text-secondary-foreground border-none hover:bg-secondary/80">
                                <Ellipsis class="size-4" />
                                {move || format!("Toplu İşlem ({})", selected_count.get())}
                            </DropdownMenuTrigger>
                            <DropdownMenuContent class="w-48">
                                <DropdownMenuLabel>"Seçili Torrentler"</DropdownMenuLabel>
                                <DropdownMenuGroup class="mt-2">
                                    <DropdownMenuItem on:click=move |_| bulk_action("start")>
                                        <Play class="mr-2 size-4" /> "Başlat"
                                    </DropdownMenuItem>
                                    <DropdownMenuItem on:click=move |_| bulk_action("stop")>
                                        <Square class="mr-2 size-4" /> "Durdur"
                                    </DropdownMenuItem>
                                    
                                    <div class="my-1 h-px bg-border" />
                                    
                                    <AlertDialog>
                                        <AlertDialogTrigger class="w-full text-left">
                                            <div class="inline-flex gap-2 items-center w-full rounded-sm px-2 py-1.5 text-sm transition-colors text-destructive hover:bg-destructive/10 focus:bg-destructive/10">
                                                <Trash2 class="size-4" /> "Toplu Sil"
                                            </div>
                                        </AlertDialogTrigger>
                                        <AlertDialogContent>
                                            <AlertDialogHeader>
                                                <AlertDialogTitle>"Toplu Silme Onayı"</AlertDialogTitle>
                                                <AlertDialogDescription>
                                                    {move || format!("Seçili {} torrent silinecek. Bu işlem geri alınamaz.", selected_count.get())}
                                                </AlertDialogDescription>
                                            </AlertDialogHeader>
                                            <AlertDialogFooter>
                                                <AlertDialogClose>"İptal"</AlertDialogClose>
                                                <Button variant=ButtonVariant::Destructive on:click=move |_| bulk_action("delete")>
                                                    "Sil"
                                                </Button>
                                            </AlertDialogFooter>
                                        </AlertDialogContent>
                                    </AlertDialog>
                                </DropdownMenuGroup>
                            </DropdownMenuContent>
                        </DropdownMenu>
                    </Show>

                    <MultiSelect values=visible_columns>
                        <MultiSelectTrigger class="w-[140px] h-9">
                            <div class="flex items-center gap-2 text-xs">
                                <Settings2 class="size-4" />
                                "Sütunlar"
                            </div>
                        </MultiSelectTrigger>
                        <MultiSelectContent>
                            <MultiSelectGroup>
                                {ALL_COLUMNS.into_iter().map(|(id, label)| {
                                    let id_val = id.to_string();
                                    view! {
                                        <MultiSelectItem>
                                            <MultiSelectOption value=id_val.clone() attr:disabled=move || id_val == "Name">
                                                {label}
                                            </MultiSelectOption>
                                        </MultiSelectItem>
                                    }.into_any()
                                }).collect_view()}
                            </MultiSelectGroup>
                        </MultiSelectContent>
                    </MultiSelect>
                </div>
            </div>

            // --- MAIN TABLE ---
            <div class="flex-1 min-h-0 overflow-hidden">
                <DataTableWrapper class="h-full bg-card/50">
                    <div class="h-full overflow-auto">
                        <DataTable>
                            <DataTableHeader class="sticky top-0 bg-muted/80 backdrop-blur-sm z-10">
                                <DataTableRow class="hover:bg-transparent">
                                    <DataTableHead class="w-12 px-4">
                                        <Checkbox
                                            checked=Signal::derive(move || {
                                                let hashes = filtered_hashes.get();
                                                !hashes.is_empty() && selected_count.get() == hashes.len()
                                            })
                                            on_checked_change=handle_select_all
                                        />
                                    </DataTableHead>
                                    
                                    {move || visible_columns.get().contains("Name").then(|| view! {
                                        <DataTableHead class="cursor-pointer group select-none" on:click=move |_| handle_sort(SortColumn::Name)>
                                            <div class="flex items-center gap-2">"Name" {move || sort_icon(SortColumn::Name)}</div>
                                        </DataTableHead>
                                    }).into_any()}
                                    
                                    {move || visible_columns.get().contains("Size").then(|| view! {
                                        <DataTableHead class="w-24 cursor-pointer group select-none" on:click=move |_| handle_sort(SortColumn::Size)>
                                            <div class="flex items-center gap-2">"Size" {move || sort_icon(SortColumn::Size)}</div>
                                        </DataTableHead>
                                    }).into_any()}
                                    
                                    {move || visible_columns.get().contains("Progress").then(|| view! {
                                        <DataTableHead class="w-48 cursor-pointer group select-none" on:click=move |_| handle_sort(SortColumn::Progress)>
                                            <div class="flex items-center gap-2">"Progress" {move || sort_icon(SortColumn::Progress)}</div>
                                        </DataTableHead>
                                    }).into_any()}
                                    
                                    {move || visible_columns.get().contains("Status").then(|| view! {
                                        <DataTableHead class="w-24 cursor-pointer group select-none" on:click=move |_| handle_sort(SortColumn::Status)>
                                            <div class="flex items-center gap-2">"Status" {move || sort_icon(SortColumn::Status)}</div>
                                        </DataTableHead>
                                    }).into_any()}
                                    
                                    {move || visible_columns.get().contains("DownSpeed").then(|| view! {
                                        <DataTableHead class="w-24 cursor-pointer group select-none text-right" on:click=move |_| handle_sort(SortColumn::DownSpeed)>
                                            <div class="flex items-center justify-end gap-2">"DL Speed" {move || sort_icon(SortColumn::DownSpeed)}</div>
                                        </DataTableHead>
                                    }).into_any()}
                                    
                                    {move || visible_columns.get().contains("UpSpeed").then(|| view! {
                                        <DataTableHead class="w-24 cursor-pointer group select-none text-right" on:click=move |_| handle_sort(SortColumn::UpSpeed)>
                                            <div class="flex items-center justify-end gap-2">"UP Speed" {move || sort_icon(SortColumn::UpSpeed)}</div>
                                        </DataTableHead>
                                    }).into_any()}
                                    
                                    {move || visible_columns.get().contains("ETA").then(|| view! {
                                        <DataTableHead class="w-24 cursor-pointer group select-none text-right" on:click=move |_| handle_sort(SortColumn::ETA)>
                                            <div class="flex items-center justify-end gap-2">"ETA" {move || sort_icon(SortColumn::ETA)}</div>
                                        </DataTableHead>
                                    }).into_any()}
                                    
                                    {move || visible_columns.get().contains("AddedDate").then(|| view! {
                                        <DataTableHead class="w-32 cursor-pointer group select-none text-right" on:click=move |_| handle_sort(SortColumn::AddedDate)>
                                            <div class="flex items-center justify-end gap-2">"Date" {move || sort_icon(SortColumn::AddedDate)}</div>
                                        </DataTableHead>
                                    }).into_any()}
                                </DataTableRow>
                            </DataTableHeader>
                            <DataTableBody>
                                <Show
                                    when=move || !filtered_hashes.get().is_empty()
                                    fallback=move || view! {
                                        <DataTableRow class="hover:bg-transparent">
                                            <DataTableCell attr:colspan="10" class="h-[400px]">
                                                <Empty class="h-full">
                                                    <EmptyHeader>
                                                        <EmptyMedia variant=EmptyMediaVariant::Icon>
                                                            <Inbox class="size-10 text-muted-foreground" />
                                                        </EmptyMedia>
                                                        <EmptyTitle>"Torrent Bulunamadı"</EmptyTitle>
                                                        <EmptyDescription>
                                                            {move || {
                                                                let query = store.search_query.get();
                                                                if query.is_empty() { "Henüz torrent bulunmuyor.".to_string() }
                                                                else { "Arama kriterlerinize uygun sonuç bulunamadı.".to_string() }
                                                            }}
                                                        </EmptyDescription>
                                                    </EmptyHeader>
                                                </Empty>
                                            </DataTableCell>
                                        </DataTableRow>
                                    }.into_any()
                                >
                                    <For each=move || filtered_hashes.get() key=|hash| hash.clone() children={
                                        let on_action = on_action.clone();
                                        move |hash| {
                                            let h = hash.clone();
                                            let is_selected = Signal::derive(move || {
                                                selected_hashes.with(|selected| selected.contains(&h))
                                            });
                                            let h_for_change = hash.clone();
                                            view! { 
                                                <TorrentRow 
                                                    hash=hash.clone() 
                                                    on_action=on_action.clone() 
                                                    is_selected=is_selected
                                                    visible_columns=visible_columns
                                                    on_select=Callback::new(move |checked| {
                                                        selected_hashes.update(|selected| {
                                                            if checked { selected.insert(h_for_change.clone()); }
                                                            else { selected.remove(&h_for_change); }
                                                        });
                                                    })
                                                /> 
                                            }
                                        }
                                    } />
                                </Show>
                            </DataTableBody>
                        </DataTable>
                    </div>
                </DataTableWrapper>
            </div>

            <div class="hidden md:flex items-center justify-between px-2 py-1 text-[11px] text-muted-foreground bg-muted/20 border rounded-md">
                <div class="flex gap-4">
                    <span>{move || format!("Toplam: {} torrent", filtered_hashes.get().len())}</span>
                    <Show when=move || has_selection.get()>
                        <span class="text-primary font-medium">{move || format!("{} torrent seçili", selected_count.get())}</span>
                    </Show>
                </div>
                <div>"VibeTorrent v3"</div>
            </div>
        </div>
    }.into_any()
}

#[component]
fn TorrentRow(
    hash: String,
    on_action: Callback<(String, String)>,
    is_selected: Signal<bool>,
    visible_columns: RwSignal<HashSet<String>>,
    on_select: Callback<bool>,
) -> impl IntoView {
    let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
    let h = hash.clone();
    let torrent = Memo::new(move |_| store.torrents.with(|map| map.get(&h).cloned()));

    let stored_hash = StoredValue::new(hash.clone());

    view! {
        <Show when=move || torrent.get().is_some() fallback=|| ()>
            {
                let on_action = on_action.clone();
                move || {
                    let t = torrent.get().unwrap();
                    let t_name = t.name.clone();
                    let status_color = match t.status { shared::TorrentStatus::Seeding => "text-green-500", shared::TorrentStatus::Downloading => "text-blue-500", shared::TorrentStatus::Paused => "text-yellow-500", shared::TorrentStatus::Error => "text-red-500", _ => "text-muted-foreground" };
                    
                    let is_active_selection = Memo::new(move |_| {
                        let selected = store.selected_torrent.get();
                        selected.as_deref() == Some(stored_hash.get_value().as_str())
                    });

                    let t_name_stored = StoredValue::new(t_name.clone());
                    let h_for_menu = stored_hash.get_value();

                    view! {
                        <TorrentContextMenu torrent_hash=h_for_menu on_action=on_action.clone()>
                            <DataTableRow 
                                class="cursor-pointer group h-10"
                                attr:data-state=move || if is_selected.get() || is_active_selection.get() { "selected" } else { "" }
                                on:click=move |_| store.selected_torrent.set(Some(stored_hash.get_value()))
                            >
                                <DataTableCell class="w-12 px-4">
                                    <Checkbox 
                                        checked=is_selected 
                                        on_checked_change=on_select 
                                    />
                                </DataTableCell>
                                
                                {move || visible_columns.get().contains("Name").then({
                                    move || view! {
                                        <DataTableCell class="font-medium truncate max-w-[200px] lg:max-w-md" attr:title=t_name_stored.get_value()>
                                            {t_name_stored.get_value()}
                                        </DataTableCell>
                                    }
                                }).into_any()}

                                {move || visible_columns.get().contains("Size").then({
                                    let size_bytes = t.size;
                                    move || {
                                        let size_str = format_bytes(size_bytes);
                                        view! { <DataTableCell class="font-mono text-xs text-muted-foreground whitespace-nowrap">{size_str}</DataTableCell> }
                                    }
                                }).into_any()}

                                {move || visible_columns.get().contains("Progress").then({
                                    let percent = t.percent_complete;
                                    move || view! {
                                        <DataTableCell>
                                            <div class="flex items-center gap-2">
                                                <div class="h-1.5 w-full bg-secondary rounded-full overflow-hidden min-w-[80px]">
                                                    <div class="h-full bg-primary transition-all duration-500" style=format!("width: {}%", percent)></div>
                                                </div>
                                                <span class="text-[10px] text-muted-foreground w-10 text-right">{format!("{:.1}%", percent)}</span>
                                            </div>
                                        </DataTableCell>
                                    }
                                }).into_any()}

                                {move || visible_columns.get().contains("Status").then({
                                    let status_text = format!("{:?}", t.status);
                                    let color = status_color;
                                    move || view! { <DataTableCell class={format!("text-xs font-semibold whitespace-nowrap {}", color)}>{status_text.clone()}</DataTableCell> }
                                }).into_any()}

                                {move || visible_columns.get().contains("DownSpeed").then({
                                    let rate = t.down_rate;
                                    move || {
                                        let speed_str = format_speed(rate);
                                        view! { <DataTableCell class="text-right font-mono text-xs text-green-600 dark:text-green-500 whitespace-nowrap">{speed_str}</DataTableCell> }
                                    }
                                }).into_any()}

                                {move || visible_columns.get().contains("UpSpeed").then({
                                    let rate = t.up_rate;
                                    move || {
                                        let speed_str = format_speed(rate);
                                        view! { <DataTableCell class="text-right font-mono text-xs text-blue-600 dark:text-blue-500 whitespace-nowrap">{speed_str}</DataTableCell> }
                                    }
                                }).into_any()}

                                {move || visible_columns.get().contains("ETA").then({
                                    let eta = t.eta;
                                    move || {
                                        let eta_str = format_duration(eta);
                                        view! { <DataTableCell class="text-right font-mono text-xs text-muted-foreground whitespace-nowrap">{eta_str}</DataTableCell> }
                                    }
                                }).into_any()}

                                {move || visible_columns.get().contains("AddedDate").then({
                                    let date = t.added_date;
                                    move || {
                                        let date_str = format_date(date);
                                        view! { <DataTableCell class="text-right font-mono text-xs text-muted-foreground whitespace-nowrap">{date_str}</DataTableCell> }
                                    }
                                }).into_any()}
                            </DataTableRow>
                        </TorrentContextMenu>
                    }.into_any()
                }
            }
        </Show>
    }.into_any()
}

#[component]
fn TorrentCard(
    hash: String,
    on_action: Callback<(String, String)>,
) -> impl IntoView {
    let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
    let h = hash.clone();
    let torrent = Memo::new(move |_| store.torrents.with(|map| map.get(&h).cloned()));

    let stored_hash = StoredValue::new(hash.clone());

    view! {
        <Show when=move || torrent.get().is_some() fallback=|| ()>
            {
                let on_action = on_action.clone();
                move || {
                    let t = torrent.get().unwrap();
                    let t_name = t.name.clone();
                    let status_badge_class = match t.status { shared::TorrentStatus::Seeding => "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400 border-green-200 dark:border-green-800", shared::TorrentStatus::Downloading => "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 border-blue-200 dark:border-blue-800", shared::TorrentStatus::Paused => "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400 border-yellow-200 dark:border-yellow-800", shared::TorrentStatus::Error => "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400 border-red-200 dark:border-red-800", _ => "bg-muted text-muted-foreground" };
                    let h_for_menu = stored_hash.get_value();

                    view! {
                        <TorrentContextMenu torrent_hash=h_for_menu on_action=on_action.clone()>
                            <div
                                class=move || {
                                    let selected = store.selected_torrent.get();
                                    let is_selected = selected.as_deref() == Some(stored_hash.get_value().as_str());
                                    if is_selected {
                                        "ring-2 ring-primary rounded-lg transition-all"
                                    } else {
                                        "transition-all"
                                    }
                                }
                                on:click=move |_| store.selected_torrent.set(Some(stored_hash.get_value()))
                            >
                            <Card class="h-full select-none cursor-pointer hover:border-primary transition-colors">
                                <CardHeader class="p-3 pb-0">
                                    <div class="flex justify-between items-start gap-2">
                                        <CardTitle class="text-sm font-medium leading-tight line-clamp-2">{t_name.clone()}</CardTitle>
                                        <div class={format!("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 {}", status_badge_class)}>{format!("{:?}", t.status)}</div>
                                    </div>
                                </CardHeader>
                                <CardBody class="p-3 pt-2 gap-3 flex flex-col">
                                    <div class="flex flex-col gap-1">
                                        <div class="flex justify-between text-[10px] text-muted-foreground">
                                            <span>{format_bytes(t.size)}</span>
                                            <span>{format!("{:.1}%", t.percent_complete)}</span>
                                        </div>
                                        <div class="h-1.5 w-full bg-secondary rounded-full overflow-hidden">
                                            <div class="h-full bg-primary transition-all duration-500" style=format!("width: {}%", t.percent_complete)></div>
                                        </div>
                                    </div>
                                    <div class="grid grid-cols-4 gap-2 text-[10px] font-mono text-muted-foreground pt-1 border-t border-border/50">
                                        <div class="flex flex-col text-blue-600 dark:text-blue-500"><span>"DL"</span><span>{format_speed(t.down_rate)}</span></div>
                                        <div class="flex flex-col text-green-600 dark:text-green-500"><span>"UP"</span><span>{format_speed(t.up_rate)}</span></div>
                                        <div class="flex flex-col"><span>"ETA"</span><span>{format_duration(t.eta)}</span></div>
                                        <div class="flex flex-col text-right"><span>"DATE"</span><span>{format_date(t.added_date)}</span></div>
                                    </div>
                                </CardBody>
                            </Card>
                            </div>
                        </TorrentContextMenu>
                    }.into_any()
                }
            }
        </Show>
    }.into_any()
}