//! Tree-sitter extractors split into two layers:
//!
//! - [`lang`] — pure language extraction (decls, imports, calls, type
//!   bindings). One module per supported language.
//! - [`framework`] — framework-specific overlays that extend a language
//!   (Axum routes for Rust, FastAPI/Flask routes for Python, the entire
//!   Rails DSL for Ruby). Frameworks are called by their language module
//!   when a known framework call shape appears in the AST.
//!
//! Adding a new framework: create `framework/<name>.rs`, expose detector
//! functions, and call them from the relevant `lang/<x>.rs` walk.

use std::path::Path;

use ckg_core::{Edge, Symbol};

pub mod framework;
pub mod lang;
pub mod schema;
pub(crate) mod util;
#[allow(dead_code)]
pub(crate) mod qname;

/// Output of a single-file extraction pass.
#[derive(Debug, Default)]
pub struct ParseOutput {
    pub symbols: Vec<Symbol>,
    pub edges: Vec<Edge>,
}

/// Detect language / schema label from file path.
pub fn detect_language(path: &Path) -> Option<&'static str> {
    let ext = path.extension()?.to_str()?;
    let stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or("");
    match ext {
        "rs" => Some("rust"),
        "py" | "pyi" => Some("python"),
        "rb" | "rake" => Some("ruby"),
        "js" | "mjs" | "cjs" | "jsx" => Some("javascript"),
        "ts" | "mts" | "cts" => Some("typescript"),
        "tsx" => Some("tsx"),
        "go" => Some("go"),
        "proto" => Some("proto"),
        "graphql" | "gql" => Some("graphql"),
        // OpenAPI: only files clearly named so to avoid catching every yaml.
        "yaml" | "yml" | "json" if stem.contains("openapi") || stem.contains("swagger") => {
            Some("openapi")
        }
        _ => None,
    }
}

/// Dispatch extraction by language / schema label.
pub fn extract(
    repo_id: &str,
    label: &str,
    path: &Path,
    source: &str,
) -> ckg_core::Result<ParseOutput> {
    match label {
        "rust" => lang::rust::extract(repo_id, path, source),
        "python" => lang::python::extract(repo_id, path, source),
        "ruby" => lang::ruby::extract(repo_id, path, source),
        "javascript" => lang::javascript::extract(repo_id, path, source, "javascript"),
        "typescript" => lang::javascript::extract(repo_id, path, source, "typescript"),
        "tsx" => lang::javascript::extract(repo_id, path, source, "tsx"),
        "go" => lang::go::extract(repo_id, path, source),
        "proto" => schema::proto::extract(repo_id, path, source),
        "graphql" => schema::graphql::extract(repo_id, path, source),
        "openapi" => schema::openapi::extract(repo_id, path, source),
        other => Err(ckg_core::Error::UnsupportedLanguage(other.to_string())),
    }
}
