// main.rs
//
// Copyright 2017 Jordan Petridis <jpetridis@gnome.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: GPL-3.0-or-later

use gtk::{gio, glib};

#[macro_use]
extern crate log;

#[macro_use]
extern crate html5ever;

// Exports the macros defined in utils to the namespace of the crate so they can be used
// easily without import
#[macro_use]
mod utils;

// Auto generated by meson.build
#[rustfmt::skip]
mod config;

mod app;
mod chapter_parser;
mod download_covers;
mod episode_description_parser;
mod feed_manager;
mod i18n;
mod manager;
mod settings;
mod thumbnail_generator;
mod widgets;
mod window;

use crate::app::PdApplication;
pub use crate::thumbnail_generator::ThumbSize::*;

use std::sync::LazyLock;

// tokio should be used when doing http fetches, since reqwest depens on it.
pub static RUNTIME: LazyLock<tokio::runtime::Runtime> =
    LazyLock::new(|| tokio::runtime::Runtime::new().unwrap());

pub static MAINCONTEXT: LazyLock<glib::MainContext> = LazyLock::new(glib::MainContext::default);
pub static CHRONO_LOCALE: LazyLock<chrono::Locale> = LazyLock::new(|| {
    use std::str::FromStr;
    let system_locale = locale_config::Locale::current();
    let time_locale = system_locale.tags_for("time").next();
    let time_locale_str = time_locale.as_ref().map(|l| l.as_ref()).unwrap_or("C");
    let unix_formatted = time_locale_str.replace('-', "_");
    chrono::Locale::from_str(&unix_formatted).unwrap_or(chrono::Locale::POSIX)
});

#[cfg(test)]
fn init_gtk_tests() -> anyhow::Result<()> {
    gst::init()?;
    gtk::init()?;
    adw::init()?;
    register_resources()?;
    Ok(())
}

fn main() -> glib::ExitCode {
    pretty_env_logger::init();
    gst::init().expect("Error initializing gstreamer");
    gtk::init().expect("Error initializing gtk.");
    register_resources().expect("Error registering resources");

    PdApplication::run()
}

fn register_resources() -> anyhow::Result<()> {
    // Create Resource it will live as long the value lives.
    let gbytes = glib::Bytes::from_static(crate::config::RESOURCEFILE);
    let resource = gio::Resource::from_data(&gbytes)?;

    // Register the resource so it won't be dropped and will continue to live in
    // memory.
    gio::resources_register(&resource);

    Ok(())
}

#[test]
// Even while running the tests with -j 1 and --test-threads=1,
// cargo seems to create new threads and gtk refuses to initialize again.
// So we run every gtk related test here.
fn test_stuff() -> anyhow::Result<()> {
    use crate::widgets::*;

    init_gtk_tests()?;

    // If a widget does not exist in the `GtkBuilder`(.ui) file this should panic and fail.
    BaseView::default();
    ShowWidget::default();
    HomeEpisode::default();
    EpisodeWidget::default();

    show_menu::ShowMenu::default();
    episode_menu::EpisodeMenu::default();

    Ok(())
}
