//! Hello-World seed for fresh installs.
//!
//! Idempotent. Runs after migrations and after admin bootstrap. Only
//! seeds when the default app is empty (no scripts, no routes); on
//! upgrades it does nothing so existing content isn't polluted.

use std::sync::Arc;

use picloud_shared::{App, AppId, HostKind, PathKind, ScriptOwner};

use crate::app_repo::AppRepository;
use crate::repo::{NewScript, ScriptRepository, ScriptRepositoryError};
use crate::route_repo::{NewRoute, RouteRepository};

const HELLO_RHAI_SOURCE: &str = include_str!("../seeds/hello.rhai");

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HelloWorldOutcome {
    /// Default app already has scripts (or doesn't exist) — left alone.
    SkippedExisting,
    /// Inserted the hello.rhai script and the `/hello` route.
    Seeded,
}

#[derive(Debug, thiserror::Error)]
pub enum SeedError {
    #[error("default app not found — did the migration run?")]
    MissingDefaultApp,
    #[error("repository error: {0}")]
    Repo(#[from] ScriptRepositoryError),
}

pub async fn seed_hello_world_if_fresh(
    apps: Arc<dyn AppRepository>,
    scripts: Arc<dyn ScriptRepository>,
    routes: Arc<dyn RouteRepository>,
) -> Result<HelloWorldOutcome, SeedError> {
    let default = apps
        .get_by_slug("default")
        .await?
        .ok_or(SeedError::MissingDefaultApp)?;

    // Idempotence: only seed when both scripts AND routes are empty.
    // (Either alone is suspicious enough to skip — the operator may have
    // already started shaping the default app.)
    let existing_scripts = scripts.list_for_app(default.id).await?;
    let existing_routes = routes.list_for_app(default.id).await?;
    if !existing_scripts.is_empty() || !existing_routes.is_empty() {
        return Ok(HelloWorldOutcome::SkippedExisting);
    }

    seed_into(&*scripts, &*routes, &default).await?;
    Ok(HelloWorldOutcome::Seeded)
}

async fn seed_into(
    scripts: &dyn ScriptRepository,
    routes: &dyn RouteRepository,
    default: &App,
) -> Result<(), ScriptRepositoryError> {
    let script = scripts
        .create(NewScript {
            app_id: Some(default.id),
            group_id: None,
            name: "hello".to_string(),
            description: Some("Reference example: returns a greeting at GET /hello.".to_string()),
            source: HELLO_RHAI_SOURCE.to_string(),
            kind: picloud_shared::ScriptKind::Endpoint,
            timeout_seconds: Some(5),
            memory_limit_mb: None,
            sandbox: None,
            enabled: true,
            imports: Vec::new(),
        })
        .await?;

    routes
        .create(NewRoute {
            owner: ScriptOwner::App(default.id),
            script_id: script.id,
            host_kind: HostKind::Any,
            host: String::new(),
            host_param_name: None,
            path_kind: PathKind::Exact,
            path: "/hello".to_string(),
            // Accept any method so both `curl /hello` and
            // `curl -d '{"name":"X"}' /hello` work out of the box.
            method: None,
            dispatch_mode: picloud_shared::DispatchMode::Sync,
            enabled: true,
            sealed: false,
        })
        .await?;

    Ok(())
}

#[allow(dead_code)]
fn _typecheck(_id: AppId) {} // suppress unused-import warnings if reshuffled
