// Copyright (C) 2026 Ordinary Labs, LLC.
//
// SPDX-License-Identifier: AGPL-3.0-only

use crate::ProvisionMode;
use ordinary_api::server::OrdinaryApiServer;
use ordinary_config::RedactedHashAlg;
use ordinary_utils::shutdown_signal;
use std::net::Ipv6Addr;
use std::path::Path;
use tokio::net::TcpListener;

#[allow(clippy::fn_params_excessive_bools, clippy::too_many_arguments)]
pub async fn run(
    environment: &str,
    data_dir: &str,
    storage_size: usize,
    log_size: bool,
    insecure: bool,
    insecure_cookies: bool,
    log_headers: bool,
    log_ips: bool,
    port: Option<u16>,
    redirect_port: Option<u16>,
    provision: &ProvisionMode,
    log_index: bool,
    log_sync_interval_min: u64,
    log_sync_interval_max: u64,
    log_max_ttl_days: u16,
    logs_dir: &Path,
    redacted_header_hash: &str,
    dedicated_ports: bool,
    swagger: bool,
) -> anyhow::Result<()> {
    tracing::debug!("starting multi-domain...");

    let environment_path = Path::new(&data_dir).join("environments").join(environment);

    fs_err::create_dir_all(&environment_path)?;

    let server_span = tracing::info_span!("server", env = %environment, pid = std::process::id());

    tracing::debug!("constructing API server...");

    let api_server = OrdinaryApiServer::new(
        environment,
        &environment_path,
        storage_size,
        log_index,
        log_sync_interval_min,
        log_sync_interval_max,
        log_max_ttl_days,
        logs_dir,
        log_size,
        &server_span,
    )?;
    let cert_dir_path = environment_path.join("certs");

    let port = if insecure {
        port.unwrap_or(80)
    } else {
        port.unwrap_or(443)
    };

    let listener = TcpListener::bind((Ipv6Addr::UNSPECIFIED, port)).await?;

    let redirect_listener = if insecure {
        None
    } else {
        let redirect_port = redirect_port.unwrap_or(80);

        Some(TcpListener::bind((Ipv6Addr::UNSPECIFIED, redirect_port)).await?)
    };

    tracing::debug!("starting API server...");

    let redacted_hash = match redacted_header_hash {
        "blake2" => Some(RedactedHashAlg::Blake2),
        "blake3" => Some(RedactedHashAlg::Blake3),
        _ => None,
    };

    api_server
        .start(
            server_span,
            if insecure {
                ordinary_api::server::SecurityMode::Insecure
            } else {
                ordinary_api::server::SecurityMode::Secure(
                    cert_dir_path,
                    match provision {
                        ProvisionMode::Localhost => ordinary_api::server::ProvisionMode::Localhost,
                        ProvisionMode::Staging => ordinary_api::server::ProvisionMode::Staging,
                        ProvisionMode::Production => {
                            ordinary_api::server::ProvisionMode::Production
                        }
                    },
                )
            },
            listener,
            !insecure_cookies,
            log_headers,
            log_ips,
            log_size,
            redirect_listener,
            dedicated_ports,
            log_index,
            redacted_hash,
            swagger,
            shutdown_signal,
        )
        .await
}
