use capitalize::Capitalize;
use ntex::http::header;
use ntex::web;
use ntex::web::HttpRequest;
use std::cmp::Ordering;
use std::fs;
use tokio::task;

use crate::providers::all::AllProvider;
use crate::providers::hanime::HanimeProvider;
use crate::providers::okporn::OkpornProvider;
use crate::providers::perverzija::PerverzijaProvider;
use crate::providers::pmvhaven::PmvhavenProvider;
use crate::providers::pornhub::PornhubProvider;
use crate::providers::redtube::RedtubeProvider;
use crate::providers::rule34video::Rule34videoProvider;
// use crate::providers::spankbang::SpankbangProvider;
use crate::util::cache::VideoCache;
use crate::util::requester::Requester;
use crate::{DbPool, db, status::*, videos::*};
use cute::c;
use std::sync::Arc;
use crate::providers::{DynProvider, ALL_PROVIDERS};

#[derive(Debug, Clone)]
pub struct ClientVersion {
    version: u32,
    subversion: u32,
    name: String,
}

impl ClientVersion {
    pub fn new(version: u32, subversion: u32, name: String) -> ClientVersion {
        ClientVersion {
            version,
            subversion,
            name,
        }
    }

    pub fn parse(input: &str) -> Option<Self> {
        // Example input: "Hot%20Tub/22c CFNetwork/1494.0.7 Darwin/23.4.0 0.002478"
        let parts: Vec<&str> = input.split_whitespace().collect();
        if let Some(first) = parts.first() {
            let name_version: Vec<&str> = first.split('/').collect();
            let name = name_version[1];

            // Extract version and optional subversion
            let (version, subversion) =
                if let Some((v, c)) = name.split_at(name.len().saturating_sub(1)).into() {
                    match v.parse::<u32>() {
                        Ok(ver) => (ver, c.chars().next().map(|ch| ch as u32).unwrap_or(0)),
                        Err(_) => {
                            // Try parsing whole string if no subversion exists
                            match name.parse::<u32>() {
                                Ok(ver) => (ver, 0),
                                Err(_) => return None,
                            }
                        }
                    }
                } else {
                    return None;
                };

            return Some(ClientVersion {
                version: version,
                subversion: subversion,
                name: name.to_string(),
            });
        }
        None
    }
}

// Implement comparisons
impl PartialEq for ClientVersion {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}

impl Eq for ClientVersion {}

impl PartialOrd for ClientVersion {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for ClientVersion {
    fn cmp(&self, other: &Self) -> Ordering {
        self.version
            .cmp(&other.version)
            .then_with(|| self.subversion.cmp(&other.subversion))
    }
}

pub fn config(cfg: &mut web::ServiceConfig) {
    cfg.service(
        web::resource("/status")
            .route(web::post().to(status))
            .route(web::get().to(status)),
    )
    .service(
        web::resource("/videos")
            // .route(web::get().to(videos_get))
            .route(web::post().to(videos_post)),
    );
}

async fn status(req: HttpRequest) -> Result<impl web::Responder, web::Error> {
    let clientversion: ClientVersion = match req.headers().get("User-Agent") {
        Some(v) => match v.to_str() {
            Ok(useragent) => ClientVersion::parse(useragent)
                .unwrap_or_else(|| ClientVersion::new(999, 0, "999".to_string())),
            Err(_) => ClientVersion::new(999, 0, "999".to_string()),
        },
        _ => ClientVersion::new(999, 0, "999".to_string()),
    };

    let host = req
        .headers()
        .get(header::HOST)
        .and_then(|h| h.to_str().ok())
        .unwrap_or_default()
        .to_string();
    let mut status = Status::new();

    // pronhub
    status.add_channel(Channel {
        id: "pornhub".to_string(),
        name: "Pornhub".to_string(),
        description: "Pornhub Free Videos".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=pornhub.com".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "mr".to_string(),
                    title: "Most Recent".to_string(),
                },
                FilterOption {
                    id: "mv".to_string(),
                    title: "Most Viewed".to_string(),
                },
                FilterOption {
                    id: "tr".to_string(),
                    title: "Top Rated".to_string(),
                },
                FilterOption {
                    id: "lg".to_string(),
                    title: "Longest".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });
    if clientversion >= ClientVersion::new(22, 101, "22e".to_string()) {
        // pmvhaven
        status.add_channel(Channel {
            id: "pmvhaven".to_string(),
            name: "Pmvhaven".to_string(),
            description: "Explore a curated collection of captivating PMV".to_string(),
            premium: false,
            favicon: "https://www.google.com/s2/favicons?sz=64&domain=pmvhaven.com".to_string(),
            status: "active".to_string(),
            categories: vec![],
            options: vec![
                ChannelOption {
                    id: "category".to_string(),
                    title: "Category".to_string(),
                    description: "Category of PMV Video get".to_string(), //"Sort the videos by Date or Name.".to_string(),
                    systemImage: "folder".to_string(),
                    colorName: "yellow".to_string(),
                    options: vec![
                        FilterOption {
                            id: "all".to_string(),
                            title: "All".to_string(),
                        },
                        FilterOption {
                            id: "pmv".to_string(),
                            title: "PMV".to_string(),
                        },
                        FilterOption {
                            id: "hmv".to_string(),
                            title: "HMV".to_string(),
                        },
                        FilterOption {
                            id: "tiktok".to_string(),
                            title: "Tiktok".to_string(),
                        },
                        FilterOption {
                            id: "koreanbj".to_string(),
                            title: "KoreanBJ".to_string(),
                        },
                        FilterOption {
                            id: "hypno".to_string(),
                            title: "Hypno".to_string(),
                        },
                        FilterOption {
                            id: "other".to_string(),
                            title: "Other".to_string(),
                        },
                    ],
                    multiSelect: false,
                },
                ChannelOption {
                    id: "sort".to_string(),
                    title: "Filter".to_string(),
                    description: "Filter PMV Videos".to_string(),
                    systemImage: "list.number".to_string(),
                    colorName: "blue".to_string(),
                    options: vec![
                        FilterOption {
                            id: "Newest".to_string(),
                            title: "Newest".to_string(),
                        },
                        FilterOption {
                            id: "Top Rated".to_string(),
                            title: "Top Rated".to_string(),
                        },
                        FilterOption {
                            id: "Most Viewed".to_string(),
                            title: "Most Viewed".to_string(),
                        },
                    ],
                    multiSelect: false,
                },
            ],
            nsfw: true,
            cacheDuration: Some(1800),
        });
    }
    if clientversion >= ClientVersion::new(22, 97, "22a".to_string()) {
        // perverzija
        status.add_channel(Channel {
            id: "perverzija".to_string(),
            name: "Perverzija".to_string(),
            description: "Free videos from Perverzija".to_string(),
            premium: false,
            favicon: "https://www.google.com/s2/favicons?sz=64&domain=tube.perverzija.com"
                .to_string(),
            status: "active".to_string(),
            categories: vec![],
            options: vec![
                // ChannelOption {
                //     id: "sort".to_string(),
                //     title: "Sort".to_string(),
                //     description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
                //     systemImage: "list.number".to_string(),
                //     colorName: "blue".to_string(),
                //     options: vec![
                //         FilterOption {
                //             id: "date".to_string(),
                //             title: "Date".to_string(),
                //         },
                //         FilterOption {
                //             id: "name".to_string(),
                //             title: "Name".to_string(),
                //         },
                //     ],
                //     multiSelect: false,
                // },
                ChannelOption {
                    id: "featured".to_string(),
                    title: "Featured".to_string(),
                    description: "Filter Featured Videos.".to_string(),
                    systemImage: "star".to_string(),
                    colorName: "red".to_string(),
                    options: vec![
                        FilterOption {
                            id: "all".to_string(),
                            title: "No".to_string(),
                        },
                        FilterOption {
                            id: "featured".to_string(),
                            title: "Yes".to_string(),
                        },
                    ],
                    multiSelect: false,
                },
                // ChannelOption {
                //     id: "duration".to_string(),
                //     title: "Duration".to_string(),
                //     description: "Filter the videos by duration.".to_string(),
                //     systemImage: "timer".to_string(),
                //     colorName: "green".to_string(),
                //     options: vec![
                //         FilterOption {
                //             id: "short".to_string(),
                //             title: "< 1h".to_string(),
                //         },
                //         FilterOption {
                //             id: "long".to_string(),
                //             title: "> 1h".to_string(),
                //         },
                //     ],
                //     multiSelect: true,
                // },
            ],
            nsfw: true,
            cacheDuration: None,
        });
    }

    // pornzog
    status.add_channel(Channel {
        id: "pornzog".to_string(),
        name: "Pornzog".to_string(),
        description: "Watch free porn videos at PornZog Free Porn Clips. More than 1 million videos, watch for free now!".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=pornzog.com".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "recent".to_string(),
                    title: "Recent".to_string(),
                },
                FilterOption {
                    id: "relevance".to_string(),
                    title: "Relevance".to_string(),
                },
                FilterOption {
                    id: "viewed".to_string(),
                    title: "Most Viewed".to_string(),
                },
                FilterOption {
                    id: "rated".to_string(),
                    title: "Most Rated".to_string(),
                },
                FilterOption {
                    id: "longest".to_string(),
                    title: "Longest".to_string(),
                }
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: None,
    });

    // Hanime
    status.add_channel(Channel {
        id: "hanime".to_string(),
        name: "Hanime".to_string(),
        description: "Free Hentai from Hanime".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=hanime.tv".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "created_at_unix.desc".to_string(),
                    title: "Recent Upload".to_string(),
                },
                FilterOption {
                    id: "created_at_unix.asc".to_string(),
                    title: "Old Upload".to_string(),
                },
                FilterOption {
                    id: "views.desc".to_string(),
                    title: "Most Views".to_string(),
                },
                FilterOption {
                    id: "views.asc".to_string(),
                    title: "Least Views".to_string(),
                },
                FilterOption {
                    id: "likes.desc".to_string(),
                    title: "Most Likes".to_string(),
                },
                FilterOption {
                    id: "likes.asc".to_string(),
                    title: "Least Likes".to_string(),
                },
                FilterOption {
                    id: "released_at_unix.desc".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "released_at_unix.asc".to_string(),
                    title: "Old".to_string(),
                },
                FilterOption {
                    id: "title_sortable.asc".to_string(),
                    title: "A - Z".to_string(),
                },
                FilterOption {
                    id: "title_sortable.desc".to_string(),
                    title: "Z - A".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: None,
    });

    // status.add_channel(Channel {
    //     id: "spankbang".to_string(),
    //     name: "SpankBang".to_string(),
    //     description: "Popular Porn Videos - SpankBang".to_string(),
    //     premium: false,
    //     favicon: "https://www.google.com/s2/favicons?sz=64&domain=spankbang.com".to_string(),
    //     status: "active".to_string(),
    //     categories: vec![],
    //     options: vec![ChannelOption {
    //         id: "sort".to_string(),
    //         title: "Sort".to_string(),
    //         description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
    //         systemImage: "list.number".to_string(),
    //         colorName: "blue".to_string(),
    //         options: vec![
    //             FilterOption {
    //                 id: "trending_videos".to_string(),
    //                 title: "Trending".to_string(),
    //             },
    //             FilterOption {
    //                 id: "new_videos".to_string(),
    //                 title: "New".to_string(),
    //             },
    //             FilterOption {
    //                 id: "most_popular".to_string(),
    //                 title: "Popular".to_string(),
    //             },
    //         ],
    //         multiSelect: false,
    //     }],
    //     nsfw: true,
    //cacheDuration: Some(1800),
    // });

    // rule34video
    status.add_channel(Channel {
        id: "rule34video".to_string(),
        name: "Rule34Video".to_string(),
        description: "If it exists, there is porn".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=rule34video.com".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "post_date".to_string(),
                    title: "Newest".to_string(),
                },
                FilterOption {
                    id: "video_viewed".to_string(),
                    title: "Most Viewed".to_string(),
                },
                FilterOption {
                    id: "rating".to_string(),
                    title: "Top Rated".to_string(),
                },
                FilterOption {
                    id: "duration".to_string(),
                    title: "Longest".to_string(),
                },
                FilterOption {
                    id: "pseudo_random".to_string(),
                    title: "Random".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    let files = fs::read_dir("./src/providers").unwrap();
    let providers = files
        .map(|entry| entry.unwrap().file_name())
        .filter(|name| name.to_str().unwrap().ends_with(".rs"))
        .filter(|name| {
            !name.to_str().unwrap().contains("mod.rs") && !name.to_str().unwrap().contains("all.rs")
        })
        .map(|name| name.to_str().unwrap().replace(".rs", ""))
        .collect::<Vec<String>>();
    let sites = c![FilterOption {
                    id: x.to_string(),
                    title: x.capitalize().to_string(),
                }, for x in providers.iter()];

    // All
    status.add_channel(Channel {
        id: "all".to_string(),
        name: "All".to_string(),
        description: "Query from all sites of this Server".to_string(),
        premium: false,
        favicon: "https://hottub.spacemoehre.de/favicon.ico".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sites".to_string(),
            title: "Sites".to_string(),
            description: "What Sites to use".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "green".to_string(),
            options: sites,
            multiSelect: true,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // Redtube
    status.add_channel(Channel {
        id: "redtube".to_string(),
        name: "Redtube".to_string(),
        description: "Redtube brings you NEW porn videos every day for free".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=www.redtube.com".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // ok.porn
    status.add_channel(Channel {
        id: "okporn".to_string(),
        name: "Ok.porn".to_string(),
        description: "Tons of HD porno movies".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=ok.porn".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "trending".to_string(),
                    title: "Trending".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // pornhat
    status.add_channel(Channel {
        id: "pornhat".to_string(),
        name: "Pornhat".to_string(),
        description: "free HD porn videos".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=pornhat.com".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "trending".to_string(),
                    title: "Trending".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    //perfectgirls
    status.add_channel(Channel {
        id: "perfectgirls".to_string(),
        name: "Perfectgirls".to_string(),
        description: "Perfect Girls Tube".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=perfectgirls.xxx".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "trending".to_string(),
                    title: "Trending".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // okxxx
    status.add_channel(Channel {
        id: "okxxx".to_string(),
        name: "Ok.xxx".to_string(),
        description: "free porn tube!".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=ok.xxx".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "trending".to_string(),
                    title: "Trending".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // homoxxx
    status.add_channel(Channel {
        id: "homoxxx".to_string(),
        name: "Homo.xxx".to_string(),
        description: "Best Gay Porn".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=homo.xxx".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "trending".to_string(),
                    title: "Trending".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // // hentaimoon
    // status.add_channel(Channel {
    //     id: "hentaimoon".to_string(),
    //     name: "Hentai Moon".to_string(),
    //     description: "Your Hentai Sputnik".to_string(),
    //     premium: false,
    //     favicon: "https://www.google.com/s2/favicons?sz=64&domain=hentai-moon.com".to_string(),
    //     status: "active".to_string(),
    //     categories: vec![],
    //     options: vec![ChannelOption {
    //         id: "sort".to_string(),
    //         title: "Sort".to_string(),
    //         description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
    //         systemImage: "list.number".to_string(),
    //         colorName: "blue".to_string(),
    //         options: vec![
    //             FilterOption {
    //                 id: "new".to_string(),
    //                 title: "New".to_string(),
    //             },
    //             FilterOption {
    //                 id: "popular".to_string(),
    //                 title: "Popular".to_string(),
    //             },
    //             FilterOption {
    //                 id: "top-rated".to_string(),
    //                 title: "Top Rated".to_string(),
    //             },
    //         ],
    //         multiSelect: false,
    //     }],
    //     nsfw: true,
    // cacheDuration: Some(1800),
    // });

    // xxthots
    status.add_channel(Channel {
        id: "xxthots".to_string(),
        name: "XXTHOTS".to_string(),
        description: "Free XXX Onlyfans Leaks Videos".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=xxthots.com".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "top-rated".to_string(),
                    title: "Top Rated".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // porn00
    status.add_channel(Channel {
        id: "porn00".to_string(),
        name: "Porn00".to_string(),
        description: "HD Porn".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=www.porn00.org".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "top-rated".to_string(),
                    title: "Top Rated".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // freshporno
    status.add_channel(Channel {
        id: "freshporno".to_string(),
        name: "Freshporno".to_string(),
        description: "Only Fresh Free HD Porn Videos Online".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=freshporno.net".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "top-rated".to_string(),
                    title: "Top Rated".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: Some(1800),
    });

    // paradisehill
    status.add_channel(Channel {
        id: "paradisehill".to_string(),
        name: "Paradisehill".to_string(),
        description: "Porn Movies on Paradise Hill".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=en.paradisehill.cc".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![],
        nsfw: true,
        cacheDuration: None,
    });

    // youjizz
    status.add_channel(Channel {
        id: "youjizz".to_string(),
        name: "YouJizz".to_string(),
        description: "YouJizz Porntube".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=www.youjizz.com".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![ChannelOption {
            id: "sort".to_string(),
            title: "Sort".to_string(),
            description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
            systemImage: "list.number".to_string(),
            colorName: "blue".to_string(),
            options: vec![
                FilterOption {
                    id: "new".to_string(),
                    title: "New".to_string(),
                },
                FilterOption {
                    id: "popular".to_string(),
                    title: "Popular".to_string(),
                },
                FilterOption {
                    id: "top-rated".to_string(),
                    title: "Top Rated".to_string(),
                },
                FilterOption {
                    id: "top-rated-week".to_string(),
                    title: "Top Rated (Week)".to_string(),
                },
                FilterOption {
                    id: "top-rated-month".to_string(),
                    title: "Top Rated (Month)".to_string(),
                },
                FilterOption {
                    id: "trending".to_string(),
                    title: "Trending".to_string(),
                },
                FilterOption {
                    id: "random".to_string(),
                    title: "Random".to_string(),
                },
            ],
            multiSelect: false,
        }],
        nsfw: true,
        cacheDuration: None,
    });

    // noodlemagazine
    // status.add_channel(Channel {
    //     id: "noodlemagazine".to_string(),
    //     name: "Noodlemagazine".to_string(),
    //     description: "Discover the Best Adult Videos".to_string(),
    //     premium: false,
    //     favicon: "https://www.google.com/s2/favicons?sz=64&domain=noodlemagazine.com".to_string(),
    //     status: "active".to_string(),
    //     categories: vec![],
    //     options: vec![],
    //     nsfw: true,
    // cacheDuration: Some(1800),
    // });

    //missav
    status.add_channel(Channel {
        id: "missav".to_string(),
        name: "MissAV".to_string(),
        description: "Watch HD JAV Online".to_string(),
        premium: false,
        favicon: "https://www.google.com/s2/favicons?sz=64&domain=missav.ws".to_string(),
        status: "active".to_string(),
        categories: vec![],
        options: vec![
            ChannelOption {
                id: "sort".to_string(),
                title: "Sort".to_string(),
                description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
                systemImage: "list.number".to_string(),
                colorName: "blue".to_string(),
                options: vec![
                    FilterOption {
                        id: "released_at".to_string(),
                        title: "Release Date".to_string(),
                    },
                    FilterOption {
                        id: "published_at".to_string(),
                        title: "Recent Update".to_string(),
                    },
                    FilterOption {
                        id: "today_views".to_string(),
                        title: "Today Views".to_string(),
                    },
                    FilterOption {
                        id: "weekly_views".to_string(),
                        title: "Weekly Views".to_string(),
                    },
                    FilterOption {
                        id: "monthly_views".to_string(),
                        title: "Monthly Views".to_string(),
                    },
                    FilterOption {
                        id: "views".to_string(),
                        title: "Total Views".to_string(),
                    },
                ],
                multiSelect: false,
            },
            ChannelOption {
                id: "filter".to_string(),
                title: "Filter".to_string(),
                description: "Filter the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
                systemImage: "line.horizontal.3.decrease.circle".to_string(),
                colorName: "green".to_string(),
                options: vec![
                    FilterOption {
                        id: "new".to_string(),
                        title: "Recent update".to_string(),
                    },
                    FilterOption {
                        id: "release".to_string(),
                        title: "New Releases".to_string(),
                    },
                    FilterOption {
                        id: "uncensored-leak".to_string(),
                        title: "Uncensored".to_string(),
                    },
                    FilterOption {
                        id: "english-subtitle".to_string(),
                        title: "English subtitle".to_string(),
                    },
                ],
                multiSelect: false,
            },
            ChannelOption {
                id: "language".to_string(),
                title: "Language".to_string(),
                description: "What Language to fetch".to_string(), //"Sort the videos by Date or Name.".to_string(),
                systemImage: "flag.fill".to_string(),
                colorName: "gray".to_string(),
                options: vec![
                    FilterOption {
                        id: "en".to_string(),
                        title: "English".to_string(),
                    },
                    FilterOption {
                        id: "cn".to_string(),
                        title: "简体中文".to_string(),
                    },
                    FilterOption {
                        id: "ja".to_string(),
                        title: "日本語".to_string(),
                    },
                    FilterOption {
                        id: "ko".to_string(),
                        title: "한국의".to_string(),
                    },
                    FilterOption {
                        id: "ms".to_string(),
                        title: "Melayu".to_string(),
                    },
                    FilterOption {
                        id: "th".to_string(),
                        title: "ไทย".to_string(),
                    },
                    FilterOption {
                        id: "de".to_string(),
                        title: "Deutsch".to_string(),
                    },
                    FilterOption {
                        id: "fr".to_string(),
                        title: "Français".to_string(),
                    },
                    FilterOption {
                        id: "vi".to_string(),
                        title: "Tiếng Việt".to_string(),
                    },
                    FilterOption {
                        id: "id".to_string(),
                        title: "Bahasa Indonesia".to_string(),
                    },
                    FilterOption {
                        id: "fil".to_string(),
                        title: "Filipino".to_string(),
                    },
                    FilterOption {
                        id: "pt".to_string(),
                        title: "Português".to_string(),
                    },
                ],
                multiSelect: false,
            },
        ],
        nsfw: true,
        cacheDuration: None,
    });

    if clientversion >= ClientVersion::new(22, 105, "22i".to_string()) {
        //sxyprn
        status.add_channel(Channel {
            id: "sxyprn".to_string(),
            name: "SexyPorn".to_string(),
            description: "Free Porn Site".to_string(),
            premium: false,
            favicon: "https://www.google.com/s2/favicons?sz=64&domain=sxyprn.com".to_string(),
            status: "active".to_string(),
            categories: vec![],
            options: vec![
                ChannelOption {
                    id: "sort".to_string(),
                    title: "Sort".to_string(),
                    description: "Sort the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
                    systemImage: "list.number".to_string(),
                    colorName: "blue".to_string(),
                    options: vec![
                        FilterOption {
                            id: "latest".to_string(),
                            title: "Latest".to_string(),
                        },
                        FilterOption {
                            id: "views".to_string(),
                            title: "Views".to_string(),
                        },
                        FilterOption {
                            id: "rating".to_string(),
                            title: "Rating".to_string(),
                        },
                        FilterOption {
                            id: "orgasmic".to_string(),
                            title: "Orgasmic".to_string(),
                        },
                    ],
                    multiSelect: false,
                },
                ChannelOption {
                    id: "filter".to_string(),
                    title: "Filter".to_string(),
                    description: "Filter the Videos".to_string(), //"Sort the videos by Date or Name.".to_string(),
                    systemImage: "line.horizontal.3.decrease.circle".to_string(),
                    colorName: "green".to_string(),
                    options: vec![
                        FilterOption {
                            id: "top".to_string(),
                            title: "Top".to_string(),
                        },
                        FilterOption {
                            id: "other".to_string(),
                            title: "Other".to_string(),
                        },
                        FilterOption {
                            id: "all".to_string(),
                            title: "All".to_string(),
                        },
                    ],
                    multiSelect: false,
                },
            ],
            nsfw: true,
            cacheDuration: Some(1800),
        });
    }

    for provider in ALL_PROVIDERS.values() {
        status.add_channel(provider.get_channel(clientversion.clone()));
    }
    status.iconUrl = format!("http://{}/favicon.ico", host).to_string();
    Ok(web::HttpResponse::Ok().json(&status))
}

async fn videos_post(
    video_request: web::types::Json<VideosRequest>,
    cache: web::types::State<VideoCache>,
    pool: web::types::State<DbPool>,
    requester: web::types::State<Requester>,
) -> Result<impl web::Responder, web::Error> {
    let requester = requester.get_ref().clone();
    let mut conn = pool.get().expect("couldn't get db connection from pool");
    // Ensure "videos" table exists with two string columns
    if !(db::has_table(&mut conn, "videos").unwrap()) {
        let _ = db::create_table(
            &mut conn,
            "CREATE TABLE videos (id TEXT NOT NULL, url TEXT NOT NULL);",
        );
    }

    let mut videos = Videos {
        pageInfo: PageInfo {
            hasNextPage: true,
            resultsPerPage: 10,
        },
        items: vec![],
    };
    let channel: String = video_request
        .channel
        .as_deref()
        .unwrap_or("all")
        .to_string();
    let sort: String = video_request.sort.as_deref().unwrap_or("date").to_string();
    let mut query: Option<String> = video_request.query.clone();
    if video_request.query.as_deref() == Some("") {
        query = None;
    }
    let page: u8 = video_request
        .page
        .as_deref()
        .unwrap_or("1")
        .to_string()
        .parse()
        .unwrap();
    let perPage: u8 = video_request
        .perPage
        .as_deref()
        .unwrap_or("10")
        .to_string()
        .parse()
        .unwrap();
    let featured = video_request
        .featured
        .as_deref()
        .unwrap_or("all")
        .to_string();
    let provider = get_provider(channel.as_str())
        .ok_or_else(|| web::error::ErrorBadRequest("Invalid channel".to_string()))?;
    let category = video_request
        .category
        .as_deref()
        .unwrap_or("all")
        .to_string();
    let sites = video_request.sites.as_deref().unwrap_or("").to_string();
    let filter = video_request.filter.as_deref().unwrap_or("new").to_string();
    let language = video_request
        .language
        .as_deref()
        .unwrap_or("en")
        .to_string();
    let network = video_request
        .networks
        .as_deref()
        .unwrap_or("")
        .to_string();
    let stars = video_request
        .stars
        .as_deref()
        .unwrap_or("")
        .to_string();
    let categories = video_request
        .categories
        .as_deref()
        .unwrap_or("")
        .to_string();
    let duration = video_request
        .duration
        .as_deref()
        .unwrap_or("")
        .to_string();
    let options = ServerOptions {
        featured: Some(featured),
        category: Some(category),
        sites: Some(sites),
        filter: Some(filter),
        language: Some(language),
        requester: Some(requester),
        network: Some(network),
        stars: Some(stars),
        categories: Some(categories),
        duration: Some(duration),
    };
    let video_items = provider
        .get_videos(
            cache.get_ref().clone(),
            pool.get_ref().clone(),
            sort.clone(),
            query.clone(),
            page.to_string(),
            perPage.to_string(),
            options.clone(),
        )
        .await;
    videos.items = video_items.clone();
    if video_items.len() == 0 {
        videos.pageInfo = PageInfo {
            hasNextPage: false,
            resultsPerPage: 10,
        }
    }
    //###
    let next_page = page.to_string().parse::<i32>().unwrap_or(1) + 1;
    let provider_clone = provider.clone();
    let cache_clone = cache.get_ref().clone();
    let pool_clone = pool.get_ref().clone();
    let sort_clone = sort.clone();
    let query_clone = query.clone();
    let per_page_clone = perPage.to_string();
    let options_clone = options.clone();
    task::spawn_local(async move {
        // if let AnyProvider::Spankbang(_) = provider_clone {
        //     // Spankbang has a delay for the next page
        //     ntex::time::sleep(ntex::time::Seconds(80)).await;
        // }
        let _ = provider_clone
            .get_videos(
                cache_clone,
                pool_clone,
                sort_clone,
                query_clone,
                next_page.to_string(),
                per_page_clone,
                options_clone,
            )
            .await;
    });
    //###

    for video in videos.items.iter_mut() {
        if video.duration <= 120 {
            let mut preview_url = video.url.clone();
            if let Some(x) = &video.formats {
                // preview is a String here, so use it directly
                preview_url = x[0].url.clone();
            }
            video.preview = Some(preview_url);
        }
    }

    Ok(web::HttpResponse::Ok().json(&videos))
}

pub fn get_provider(channel: &str) -> Option<DynProvider> {
    match channel {
        "all" => Some(Arc::new(AllProvider::new())),
        "perverzija" => Some(Arc::new(PerverzijaProvider::new())),
        "hanime" => Some(Arc::new(HanimeProvider::new())),
        "pornhub" => Some(Arc::new(PornhubProvider::new())),
        "pmvhaven" => Some(Arc::new(PmvhavenProvider::new())),
        "rule34video" => Some(Arc::new(Rule34videoProvider::new())),
        "redtube" => Some(Arc::new(RedtubeProvider::new())),
        "okporn" => Some(Arc::new(OkpornProvider::new())),
        "pornhat" => Some(Arc::new(crate::providers::pornhat::PornhatProvider::new())),
        "perfectgirls" => Some(Arc::new(
            crate::providers::perfectgirls::PerfectgirlsProvider::new(),
        )),
        "okxxx" => Some(Arc::new(crate::providers::okxxx::OkxxxProvider::new())),
        "homoxxx" => Some(Arc::new(crate::providers::homoxxx::HomoxxxProvider::new())),
        "missav" => Some(Arc::new(crate::providers::missav::MissavProvider::new())),
        "xxthots" => Some(Arc::new(crate::providers::xxthots::XxthotsProvider::new())),
        "sxyprn" => Some(Arc::new(crate::providers::sxyprn::SxyprnProvider::new())),
        "porn00" => Some(Arc::new(crate::providers::porn00::Porn00Provider::new())),
        "freshporno" => Some(Arc::new(
            crate::providers::freshporno::FreshpornoProvider::new(),
        )),
        "youjizz" => Some(Arc::new(crate::providers::youjizz::YoujizzProvider::new())),
        "paradisehill" => Some(Arc::new(
            crate::providers::paradisehill::ParadisehillProvider::new(),
        )),
        "pornzog" => Some(Arc::new(crate::providers::pornzog::PornzogProvider::new())),
        // fallback to the dynamic registry
        x => ALL_PROVIDERS.get(x).cloned(),
    }
}
