use actix_cors::Cors;
use actix_multipart::form::tempfile::TempFileConfig;
use actix_remote_ip::RemoteIPConfig;
use actix_web::middleware::Logger;
use actix_web::{App, HttpServer, web};
use geneit_backend::app_config::AppConfig;
use geneit_backend::connections::{db_connection, s3_connection};
use geneit_backend::controllers::{
    accommodations_list_controller, accommodations_reservations_calendars_controller,
    accommodations_reservations_controller, auth_controller, couples_controller, data_controller,
    families_controller, members_controller, photos_controller, server_controller,
    users_controller,
};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));

    log::info!("Start to listen on {}", AppConfig::get().listen_address);

    // Initialize bucket
    log::info!("Initialize bucket");
    s3_connection::create_bucket_if_required()
        .await
        .expect("Failed to initialize S3 bucket!");

    // Initialize database connection
    log::debug!("Initialize database connection");
    db_connection::initialize_conn().expect("Failed to initialize database connection!");

    HttpServer::new(|| {
        App::new()
            .wrap(
                Cors::default()
                    .allowed_origin(&AppConfig::get().website_origin)
                    .allowed_methods(vec!["GET", "POST", "PUT", "PATCH", "DELETE"])
                    .allowed_header("X-Auth-Token")
                    .allow_any_header()
                    .supports_credentials()
                    .max_age(3600),
            )
            .wrap(Logger::default())
            .app_data(web::Data::new(RemoteIPConfig {
                proxy: AppConfig::get().proxy_ip.clone(),
            }))
            // Uploaded files
            .app_data(TempFileConfig::default().directory(&AppConfig::get().temp_dir))
            // Config controller
            .route("/", web::get().to(server_controller::home))
            .route(
                "/server/config",
                web::get().to(server_controller::server_config),
            )
            // Auth controller
            .route(
                "/auth/create_account",
                web::post().to(auth_controller::create_account),
            )
            .route(
                "/auth/request_reset_password",
                web::post().to(auth_controller::request_reset_password),
            )
            .route(
                "/auth/check_reset_password_token",
                web::post().to(auth_controller::check_reset_password_token),
            )
            .route(
                "/auth/reset_password",
                web::post().to(auth_controller::reset_password),
            )
            .route(
                "/auth/password_login",
                web::post().to(auth_controller::password_login),
            )
            .route(
                "/auth/start_openid_login",
                web::post().to(auth_controller::start_openid_login),
            )
            .route(
                "/auth/finish_openid_login",
                web::post().to(auth_controller::finish_openid_login),
            )
            .route("/auth/logout", web::get().to(auth_controller::logout))
            // User controller
            .route("/user/info", web::get().to(users_controller::auth_info))
            .route(
                "/user/update_profile",
                web::post().to(users_controller::update_profile),
            )
            .route(
                "/user/replace_password",
                web::post().to(users_controller::replace_password),
            )
            .route(
                "/user/request_delete",
                web::get().to(users_controller::request_delete_account),
            )
            .route(
                "/user/check_delete_token",
                web::post().to(users_controller::check_delete_token),
            )
            .route(
                "/user/delete_account",
                web::post().to(users_controller::delete_account),
            )
            // Families controller
            .route(
                "/family/create",
                web::post().to(families_controller::create),
            )
            .route("/family/join", web::post().to(families_controller::join))
            .route("/family/list", web::get().to(families_controller::list))
            .route(
                "/family/{id}",
                web::get().to(families_controller::single_info),
            )
            .route(
                "/family/{id}/leave",
                web::post().to(families_controller::leave),
            )
            .route("/family/{id}", web::patch().to(families_controller::update))
            .route(
                "/family/{id}",
                web::delete().to(families_controller::delete),
            )
            .route(
                "/family/{id}/renew_invitation_code",
                web::post().to(families_controller::renew_invitation_code),
            )
            .route(
                "/family/{id}/users",
                web::get().to(families_controller::users),
            )
            .route(
                "/family/{id}/user/{user_id}",
                web::patch().to(families_controller::update_membership),
            )
            .route(
                "/family/{id}/user/{user_id}",
                web::delete().to(families_controller::delete_membership),
            )
            // [GENEALOGY] Members controller
            .route(
                "/family/{id}/genealogy/member/create",
                web::post().to(members_controller::create),
            )
            .route(
                "/family/{id}/genealogy/members",
                web::get().to(members_controller::get_all),
            )
            .route(
                "/family/{id}/genealogy/member/{member_id}",
                web::get().to(members_controller::get_single),
            )
            .route(
                "/family/{id}/genealogy/member/{member_id}",
                web::put().to(members_controller::update),
            )
            .route(
                "/family/{id}/genealogy/member/{member_id}",
                web::delete().to(members_controller::delete),
            )
            .route(
                "/family/{id}/genealogy/member/{member_id}/photo",
                web::put().to(members_controller::set_photo),
            )
            .route(
                "/family/{id}/genealogy/member/{member_id}/photo",
                web::delete().to(members_controller::remove_photo),
            )
            // [GENEALOGY] Couples controller
            .route(
                "/family/{id}/genealogy/couple/create",
                web::post().to(couples_controller::create),
            )
            .route(
                "/family/{id}/genealogy/couples",
                web::get().to(couples_controller::get_all),
            )
            .route(
                "/family/{id}/genealogy/couple/{couple_id}",
                web::get().to(couples_controller::get_single),
            )
            .route(
                "/family/{id}/genealogy/couple/{couple_id}",
                web::put().to(couples_controller::update),
            )
            .route(
                "/family/{id}/genealogy/couple/{couple_id}",
                web::delete().to(couples_controller::delete),
            )
            .route(
                "/family/{id}/genealogy/couple/{couple_id}/photo",
                web::put().to(couples_controller::set_photo),
            )
            .route(
                "/family/{id}/genealogy/couple/{couple_id}/photo",
                web::delete().to(couples_controller::remove_photo),
            )
            // [GENEALOGY] Data controller
            .route(
                "/family/{id}/genealogy/data/export",
                web::get().to(data_controller::export_family),
            )
            .route(
                "/family/{id}/genealogy/data/import",
                web::put().to(data_controller::import_family),
            )
            // [ACCOMODATIONS] List controller
            .route(
                "/family/{id}/accommodations/list/create",
                web::post().to(accommodations_list_controller::create),
            )
            .route(
                "/family/{id}/accommodations/list/list",
                web::get().to(accommodations_list_controller::get_full_list),
            )
            .route(
                "/family/{id}/accommodations/list/{accommodation_id}",
                web::get().to(accommodations_list_controller::get_single),
            )
            .route(
                "/family/{id}/accommodations/list/{accommodation_id}",
                web::put().to(accommodations_list_controller::update),
            )
            .route(
                "/family/{id}/accommodations/list/{accommodation_id}",
                web::delete().to(accommodations_list_controller::delete),
            )
            // [ACCOMODATIONS] Reservations controller
            .route(
                "/family/{id}/accommodations/reservations/accommodation/{accommodation_id}",
                web::get()
                    .to(accommodations_reservations_controller::get_accommodation_reservations),
            )
            .route(
                "/family/{id}/accommodations/reservations/accommodation/{accommodation_id}/for_interval",
                web::get()
                    .to(accommodations_reservations_controller::get_accommodation_reservations_for_interval),
            )
            .route(
                "/family/{id}/accommodations/reservations/full_list",
                web::get().to(accommodations_reservations_controller::full_list),
            )
            .route(
                "/family/{id}/accommodations/reservations/accommodation/{accommodation_id}/create",
                web::post().to(accommodations_reservations_controller::create_reservation),
            )
            .route(
                "/family/{id}/accommodations/reservation/{reservation_id}",
                web::get().to(accommodations_reservations_controller::get_single),
            )
            .route(
                "/family/{id}/accommodations/reservation/{reservation_id}",
                web::patch().to(accommodations_reservations_controller::update_single),
            )
            .route(
                "/family/{id}/accommodations/reservation/{reservation_id}",
                web::delete().to(accommodations_reservations_controller::delete),
            )
            .route(
                "/family/{id}/accommodations/reservation/{reservation_id}/validate",
                web::post().to(accommodations_reservations_controller::validate_or_reject),
            )
            // [ACCOMMODATIONS] Calendars controller
            .route(
                "/family/{id}/accommodations/reservations_calendars/create",
                web::post().to(accommodations_reservations_calendars_controller::create),
            )
            .route(
                "/family/{id}/accommodations/reservations_calendars/list",
                web::get().to(accommodations_reservations_calendars_controller::get_list),
            )
            .route(
                "/family/{id}/accommodations/reservations_calendars/{cal_id}",
                web::delete().to(accommodations_reservations_calendars_controller::delete),
            )
            .route(
                "/acccommodations_calendar/{token}",
                web::get().to(accommodations_reservations_calendars_controller::anonymous_access),
            )
            // Photos controller
            .route(
                "/photo/{id}",
                web::get().to(photos_controller::get_full_size),
            )
            .route(
                "/photo/{id}/thumbnail",
                web::get().to(photos_controller::get_thumbnail),
            )
    })
    .bind(AppConfig::get().listen_address.as_str())?
    .run()
    .await
}
