extern crate sap_sync_backend;

mod routes;

use argon2::password_hash::PasswordHasher;
use argon2::Argon2;
use postgres::NoTls;
use r2d2::Pool;
use r2d2_postgres::PostgresConnectionManager;
use rouille::{router, Request, Response};
use std::sync::Arc;

use routes::AppState;

fn main() {
    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
    dotenvy::dotenv().ok();

    let port = std::env::var("APP__SERVER__PORT")
        .unwrap_or_else(|_| "3001".to_string())
        .parse::<u16>()
        .unwrap_or(3001);

    let database_url = std::env::var("DATABASE_URL")
        .unwrap_or_else(|_| "postgresql://sap_user:papsync123@localhost:5432/sap_sync".to_string());

    let admin_username = std::env::var("ADMIN_USERNAME").unwrap_or_else(|_| "admin".to_string());
    let admin_email =
        std::env::var("ADMIN_EMAIL").unwrap_or_else(|_| "admin@sap-sync.local".to_string());
    let admin_password =
        std::env::var("ADMIN_PASSWORD").unwrap_or_else(|_| "Admin123!".to_string());

    let manager = PostgresConnectionManager::new(database_url.parse().unwrap_or_default(), NoTls);
    let pool = match Pool::builder().max_size(15).build(manager) {
        Ok(p) => p,
        Err(e) => {
            log::error!("Failed to create pool: {}", e);
            panic!("Failed to create database pool");
        }
    };

    let state = Arc::new(AppState {
        pool,
        admin_username,
        admin_email,
        admin_password,
    });

    create_admin_user(&state).expect("Failed to create admin user");

    log::info!("Listening on 0.0.0.0:{}", port);
    rouille::start_server(("0.0.0.0", port), move |request| {
        handle_request(request, &state)
    });
}

fn create_admin_user(state: &Arc<AppState>) -> Result<(), Box<dyn std::error::Error>> {
    let mut conn = state.pool.get()?;

    if conn
        .query_opt(
            "SELECT id FROM users WHERE username = $1",
            &[&state.admin_username],
        )?
        .is_some()
    {
        return Ok(());
    }

    let salt = argon2::password_hash::SaltString::generate(rand::thread_rng());
    let password_hash = Argon2::default()
        .hash_password(state.admin_password.as_bytes(), &salt)
        .map_err(|e| format!("Failed to hash admin password: {}", e))?
        .to_string();

    conn.execute(
        "INSERT INTO users (username, email, password_hash, role, is_active, mfa_enabled, failed_login_attempts) \
         VALUES ($1, $2, $3, $4, $5, $6, $7)",
        &[&state.admin_username, &state.admin_email, &password_hash, &"admin", &true, &false, &0i32],
    )?;

    log::info!("Admin user created: {}", state.admin_username);
    Ok(())
}

fn handle_request(request: &Request, state: &Arc<AppState>) -> Response {
    router!(request,

        // Health & Config
        (GET)  (/api/health) => { routes::health::get_health(request, state) },
        (GET)  (/api/config) => { routes::health::get_config(request, state) },
        (PUT)  (/api/config) => { routes::health::put_config(request, state) },

        // Authentication
        (POST) (/api/auth/login)           => { routes::auth::login(request, state) },
        (POST) (/api/auth/logout)          => { routes::auth::logout(request, state) },
        (GET)  (/api/auth/me)              => { routes::auth::me(request, state) },
        (POST) (/api/auth/change-password) => { routes::auth::change_password(request, state) },
        (POST) (/api/auth/mfa/setup)       => { routes::auth::mfa_setup(request, state) },
        (POST) (/api/auth/mfa/verify)      => { routes::auth::mfa_verify(request, state) },

        // Audit
        (GET) (/api/audit/logs)      => { routes::audit::get_logs(request, state) },
        (GET) (/api/audit/sync-logs) => { routes::audit::get_sync_logs(request, state) },
        (GET) (/api/audit/export)    => { routes::audit::export(request, state) },

        // Direct connection tests
        (POST) (/api/sap/test)   => { routes::servers::test_sap_direct(request, state) },
        (POST) (/api/plesk/test) => { routes::servers::test_plesk_direct(request, state) },

        // Plesk servers
        (GET)    (/api/servers/plesk)                    => { routes::servers::list_plesk(request, state) },
        (POST)   (/api/servers/plesk)                    => { routes::servers::create_plesk(request, state) },
        (GET)    (/api/servers/plesk/{id: String})       => { routes::servers::get_plesk(request, state, &id) },
        (PUT)    (/api/servers/plesk/{id: String})       => { routes::servers::update_plesk(request, state, &id) },
        (DELETE) (/api/servers/plesk/{id: String})       => { routes::servers::delete_plesk(request, state, &id) },
        (POST)   (/api/servers/plesk/{id: String}/test)  => { routes::servers::test_plesk(request, state, &id) },

        // SAP servers
        (GET)    (/api/servers/sap)                    => { routes::servers::list_sap(request, state) },
        (POST)   (/api/servers/sap)                    => { routes::servers::create_sap(request, state) },
        (GET)    (/api/servers/sap/{id: String})       => { routes::servers::get_sap(request, state, &id) },
        (PUT)    (/api/servers/sap/{id: String})       => { routes::servers::update_sap(request, state, &id) },
        (DELETE) (/api/servers/sap/{id: String})       => { routes::servers::delete_sap(request, state, &id) },
        (POST)   (/api/servers/sap/{id: String}/test)  => { routes::servers::test_sap(request, state, &id) },

        // Sync
        (GET)  (/api/sync/status)    => { routes::sync::get_status(request, state) },
        (POST) (/api/sync/start)     => { routes::sync::start(request, state) },
        (POST) (/api/sync/stop)      => { routes::sync::stop(request, state) },
        (GET)  (/api/sync/jobs)      => { routes::sync::list_jobs(request, state) },
        (POST) (/api/sync/simulate)  => { routes::sync::simulate(request, state) },
        (GET)  (/api/sync/conflicts) => { routes::sync::list_conflicts(request, state) },
        (POST) (/api/sync/conflicts/{id: i32}/resolve) => { routes::sync::resolve_conflict(request, state, id) },

        // Billing & Pricing
        (GET)  (/api/pricing)                        => { routes::billing::list_pricing(request, state) },
        (POST) (/api/pricing)                        => { routes::billing::create_pricing(request, state) },
        (GET)  (/api/billing/records)                => { routes::billing::list_records(request, state) },
        (POST) (/api/billing/generate)               => { routes::billing::generate(request, state) },
        (GET)  (/api/billing/preview/{id: i32})      => { routes::billing::preview(request, state, id) },
        (POST) (/api/billing/send-to-sap/{id: i32}) => { routes::billing::send_to_sap_by_id(request, state, id) },
        (POST) (/api/billing/send-to-sap)           => { routes::billing::send_to_sap(request, state) },

        // Reports / Exports
        (GET) (/api/reports/export/{format: String}) => { routes::reports::export(request, state, &format) },

        // Alerts
        (GET)    (/api/alerts/thresholds)           => { routes::alerts::list_thresholds(request, state) },
        (POST)   (/api/alerts/thresholds)           => { routes::alerts::create_threshold(request, state) },
        (PUT)    (/api/alerts/thresholds/{id: i32}) => { routes::alerts::update_threshold(request, state, id) },
        (DELETE) (/api/alerts/thresholds/{id: i32}) => { routes::alerts::delete_threshold(request, state, id) },
        (GET)    (/api/alerts/history)              => { routes::alerts::get_history(request, state) },

        // Webhooks
        (GET)    (/api/webhooks)           => { routes::webhooks::list(request, state) },
        (POST)   (/api/webhooks)           => { routes::webhooks::create(request, state) },
        (DELETE) (/api/webhooks/{id: i32}) => { routes::webhooks::delete(request, state, id) },

        // Schedules
        (GET)    (/api/schedules)           => { routes::schedules::list(request, state) },
        (POST)   (/api/schedules)           => { routes::schedules::create(request, state) },
        (PUT)    (/api/schedules/{id: i32}) => { routes::schedules::update(request, state, id) },
        (DELETE) (/api/schedules/{id: i32}) => { routes::schedules::delete(request, state, id) },

        // Setup
        (GET)  (/api/setup/status)      => { routes::setup::get_status(request, state) },
        (POST) (/api/config/test-plesk) => { routes::setup::test_plesk(request, state) },
        (POST) (/api/config/plesk2fa)   => { routes::setup::plesk_2fa(request, state) },
        (POST) (/api/config/test-sap)   => { routes::setup::test_sap(request, state) },
        (POST) (/api/config/setup)      => { routes::setup::save_config(request, state) },
        (POST) (/api/setup)             => { routes::setup::save_config(request, state) },

        // Root
        (GET) (/) => {
            Response::html("<h1>SAP Sync API</h1><p>Use /api/health to check status</p>")
        },

        _ => {
            Response::empty_404()
        }
    )
}
