use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use serde::{Deserialize, Serialize};

use crate::db;
use crate::db::schema::CozoDb;

use super::{ApiResponse, AppState};

#[derive(Deserialize, Serialize)]
pub struct QueryRequest {
    pub query: String,
}

#[derive(Serialize)]
pub struct QueryResponse {
    pub result: Vec<serde_json::Value>,
}

#[derive(Deserialize)]
pub struct SearchParams {
    pub q: Option<String>,
    pub element_type: Option<String>,
    pub file_path: Option<String>,
}

#[derive(Deserialize, Serialize)]
pub struct AnnotationRequest {
    pub element_qualified: String,
    pub description: String,
    pub user_story_id: Option<String>,
    pub feature_id: Option<String>,
}

#[derive(Serialize, Clone)]
pub struct GraphData {
    pub nodes: Vec<GraphNode>,
    pub edges: Vec<GraphEdge>,
}

#[derive(Serialize, Clone)]
pub struct GraphNode {
    pub id: String,
    pub label: String,
    pub element_type: String,
    pub file_path: String,
}

#[derive(Serialize, Clone)]
pub struct GraphEdge {
    pub source: String,
    pub target: String,
    pub rel_type: String,
}

fn build_nav_html() -> String {
    r#"
        <nav style="margin-bottom: 20px; padding: 10px; background: #f5f5f5; border-radius: 8px;">
            <a href="/" style="margin-right: 15px; text-decoration: none; color: #333; font-weight: 500;">Dashboard</a>
            <a href="/graph" style="margin-right: 15px; text-decoration: none; color: #333; font-weight: 500;">Graph</a>
            <a href="/browse" style="margin-right: 15px; text-decoration: none; color: #333; font-weight: 500;">Browse</a>
            <a href="/docs" style="margin-right: 15px; text-decoration: none; color: #333; font-weight: 500;">Docs</a>
            <a href="/annotate" style="margin-right: 15px; text-decoration: none; color: #333; font-weight: 500;">Annotate</a>
            <a href="/quality" style="margin-right: 15px; text-decoration: none; color: #333; font-weight: 500;">Quality</a>
            <a href="/export" style="margin-right: 15px; text-decoration: none; color: #333; font-weight: 500;">Export</a>
            <a href="/settings" style="text-decoration: none; color: #333; font-weight: 500;">Settings</a>
        </nav>
    "#.to_string()
}

fn base_html(title: &str, content: &str) -> String {
    format!(
        r#"<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>LeanKG - {}</title>
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <style>
        * {{ box-sizing: border-box; margin: 0; padding: 0; }}
        body {{ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 1400px; margin: 0 auto; padding: 20px; background: #fafafa; }}
        nav {{ margin-bottom: 20px; padding: 12px 20px; background: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
        nav a {{ margin-right: 20px; text-decoration: none; color: #444; font-weight: 500; transition: color 0.2s; }}
        nav a:hover {{ color: #0066cc; }}
        h1 {{ color: #333; margin-bottom: 20px; font-size: 1.8rem; }}
        h2 {{ color: #444; margin: 15px 0; font-size: 1.3rem; }}
        .card {{ background: #fff; padding: 20px; margin-bottom: 15px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
        .stats {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 20px; }}
        .stat-box {{ background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); text-align: center; }}
        .stat-box .value {{ font-size: 2rem; font-weight: 700; color: #0066cc; }}
        .stat-box .label {{ color: #666; font-size: 0.9rem; margin-top: 5px; }}
        input, select, textarea {{ width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; margin-bottom: 10px; }}
        button {{ background: #0066cc; color: #fff; padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; font-weight: 500; transition: background 0.2s; }}
        button:hover {{ background: #0052a3; }}
        table {{ width: 100%; border-collapse: collapse; }}
        th, td {{ padding: 12px; text-align: left; border-bottom: 1px solid #eee; }}
        th {{ background: #f8f9fa; font-weight: 600; color: #333; }}
        tr:hover {{ background: #f8f9fa; }}
        .badge {{ display: inline-block; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 500; }}
        .badge-function {{ background: #e3f2fd; color: #1565c0; }}
        .badge-class {{ background: #f3e5f5; color: #7b1fa2; }}
        .badge-file {{ background: #e8f5e9; color: #2e7d32; }}
        .badge-module {{ background: #fff3e0; color: #e65100; }}
        #graph-container {{ width: 100%; height: 600px; border: 1px solid #ddd; border-radius: 8px; background: #fff; }}
        .node {{ cursor: pointer; }}
        .link {{ stroke: #999; stroke-opacity: 0.6; }}
        .node circle {{ stroke: #fff; stroke-width: 2px; }}
        .node text {{ font-size: 11px; pointer-events: none; }}
        .loading {{ text-align: center; padding: 40px; color: #666; }}
        .error {{ background: #ffebee; color: #c62828; padding: 15px; border-radius: 6px; margin-bottom: 15px; }}
        .success {{ background: #e8f5e9; color: #2e7d32; padding: 15px; border-radius: 6px; margin-bottom: 15px; }}
        .form-group {{ margin-bottom: 15px; }}
        .form-group label {{ display: block; margin-bottom: 5px; font-weight: 500; color: #333; }}
    </style>
</head>
<body>
{}
<h1>{}</h1>
{}
</body>
</html>"#,
        title,
        build_nav_html(),
        title,
        content
    )
}

#[allow(dead_code)]
pub async fn index(State(state): State<AppState>) -> axum::response::Html<String> {
    let mut element_count = 0usize;
    let mut relationship_count = 0usize;
    let mut annotation_count = 0usize;
    let mut files_count = 0usize;
    let mut functions_count = 0usize;
    let mut classes_count = 0usize;

    if let Ok(graph) = state.get_graph_engine().await {
        if let Ok(elements) = graph.all_elements() {
            element_count = elements.len();
            files_count = elements.iter().filter(|x| x.element_type == "file").count();
            functions_count = elements
                .iter()
                .filter(|x| x.element_type == "function")
                .count();
            classes_count = elements
                .iter()
                .filter(|x| x.element_type == "class")
                .count();
        }
        if let Ok(relns) = graph.all_relationships() {
            relationship_count = relns.len();
        }
        if let Ok(anns) = graph.all_annotations() {
            annotation_count = anns.len();
        }
    }

    let content = format!(
        r#"
        <div class="stats">
            <div class="stat-box"><div class="value">{}</div><div class="label">Total Elements</div></div>
            <div class="stat-box"><div class="value">{}</div><div class="label">Relationships</div></div>
            <div class="stat-box"><div class="value">{}</div><div class="label">Annotations</div></div>
        </div>
        <div class="stats">
            <div class="stat-box"><div class="value">{}</div><div class="label">Files</div></div>
            <div class="stat-box"><div class="value">{}</div><div class="label">Functions</div></div>
            <div class="stat-box"><div class="value">{}</div><div class="label">Classes</div></div>
        </div>
        <div class="card">
            <h2>Getting Started</h2>
            <p style="color: #666; margin-bottom: 10px;">Use the CLI to index your codebase:</p>
            <code style="display: block; background: #f5f5f5; padding: 15px; border-radius: 6px; margin-bottom: 15px;">leankg init && leankg index ./src</code>
            <p style="color: #666;">Then start the server with:</p>
            <code style="display: block; background: #f5f5f5; padding: 15px; border-radius: 6px;">leankg serve</code>
        </div>
        <div class="card">
            <h2>Quick Actions</h2>
            <div style="display: flex; gap: 10px; flex-wrap: wrap;">
                <a href="/graph"><button>View Graph</button></a>
                <a href="/browse"><button>Browse Code</button></a>
                <a href="/annotate"><button>Add Annotation</button></a>
                <a href="/export"><button>Export Graph</button></a>
            </div>
        </div>"#,
        element_count,
        relationship_count,
        annotation_count,
        files_count,
        functions_count,
        classes_count
    );

    axum::response::Html(base_html("Dashboard", &content))
}

#[allow(dead_code)]
pub async fn graph() -> axum::response::Html<String> {
    let content = r#"
        <div class="card">
            <h2>Code Dependency Graph</h2>
            <p style="color: #666; margin-bottom: 15px;">Interactive visualization of code elements and their relationships.</p>
            <div id="graph-container"><div class="loading">Loading graph data...</div></div>
        </div>
        <div class="card">
            <h3>Graph Controls</h3>
            <div style="display: flex; gap: 10px; flex-wrap: wrap;">
                <button onclick="zoomIn()">Zoom In</button>
                <button onclick="zoomOut()">Zoom Out</button>
                <button onclick="resetZoom()">Reset</button>
                <button onclick="toggleLabels()">Toggle Labels</button>
            </div>
        </div>
        <script>
            let svg, g, zoom, nodes, labelsVisible = true;
            const width = 1400, height = 600;
            async function loadGraph() {
                try {
                    const response = await fetch('/api/graph/data');
                    const data = await response.json();
                    if (data.success && data.data) initGraph(data.data);
                    else document.getElementById('graph-container').innerHTML = '<div class="error">No graph data available. Index your codebase first.</div>';
                } catch (e) {
                    document.getElementById('graph-container').innerHTML = '<div class="error">Failed to load graph: ' + e.message + '</div>';
                }
            }
            function initGraph(graphData) {
                const container = document.getElementById('graph-container');
                container.innerHTML = '';
                svg = d3.select('#graph-container').append('svg').attr('width', '100%').attr('height', height);
                zoom = d3.zoom().scaleExtent([0.1, 4]).on('zoom', (e) => g.attr('transform', e.transform));
                svg.call(zoom);
                g = svg.append('g');
                const simulation = d3.forceSimulation(graphData.nodes)
                    .force('link', d3.forceLink(graphData.edges).id(d => d.id).distance(100))
                    .force('charge', d3.forceManyBody().strength(-300))
                    .force('center', d3.forceCenter(width / 2, height / 2))
                    .force('collision', d3.forceCollide().radius(30));
                const link = g.append('g').selectAll('line').data(graphData.edges).join('line').attr('class', 'link').attr('stroke-width', 1.5);
                const node = g.append('g').selectAll('g').data(graphData.nodes).join('g').attr('class', 'node')
                    .call(d3.drag().on('start', dragstarted).on('drag', dragged).on('end', dragended));
                const colors = {'file': '#2e7d32', 'function': '#1565c0', 'class': '#7b1fa2', 'module': '#e65100'};
                node.append('circle').attr('r', 15).attr('fill', d => colors[d.element_type] || '#666');
                node.append('text').text(d => d.label).attr('x', 20).attr('y', 5).style('display', labelsVisible ? 'block' : 'none');
                node.on('click', (e, d) => { alert('Element: ' + d.label + '\nType: ' + d.element_type + '\nFile: ' + d.file_path); });
                simulation.on('tick', () => {
                    link.attr('x1', d => d.source.x).attr('y1', d => d.source.y).attr('x2', d => d.target.x).attr('y2', d => d.target.y);
                    node.attr('transform', d => 'translate(' + d.x + ',' + d.y + ')');
                });
                nodes = node;
            }
            function dragstarted(e) { if (!e.active) simulation.alphaTarget(0.3).restart(); e.subject.fx = e.subject.x; e.subject.fy = e.subject.y; }
            function dragged(e) { e.subject.fx = e.x; e.subject.fy = e.y; }
            function dragended(e) { if (!e.active) simulation.alphaTarget(0); e.subject.fx = null; e.subject.fy = null; }
            function zoomIn() { svg.transition().call(zoom.scaleBy, 1.3); }
            function zoomOut() { svg.transition().call(zoom.scaleBy, 0.7); }
            function resetZoom() { svg.transition().call(zoom.transform, d3.zoomIdentity); }
            function toggleLabels() { labelsVisible = !labelsVisible; if (nodes) nodes.select('text').style('display', labelsVisible ? 'block' : 'none'); }
            loadGraph();
        </script>"#;

    axum::response::Html(base_html("Graph Visualization", content))
}

#[allow(dead_code)]
pub async fn browse(State(state): State<AppState>) -> axum::response::Html<String> {
    let elements: Vec<_> = if let Ok(g) = state.get_graph_engine().await {
        g.all_elements().unwrap_or_default()
    } else {
        vec![]
    };

    let mut files: Vec<_> = elements
        .iter()
        .filter(|e| e.element_type == "file")
        .collect();
    let mut functions: Vec<_> = elements
        .iter()
        .filter(|e| e.element_type == "function")
        .collect();
    let mut classes: Vec<_> = elements
        .iter()
        .filter(|e| e.element_type == "class")
        .collect();

    files.sort_by(|a, b| a.qualified_name.cmp(&b.qualified_name));
    functions.sort_by(|a, b| a.qualified_name.cmp(&b.qualified_name));
    classes.sort_by(|a, b| a.qualified_name.cmp(&b.qualified_name));

    let files_html: String = files.iter().map(|e| format!(r#"<tr><td><span class="badge badge-file">file</span></td><td><code>{}</code></td><td>{}</td><td>{}</td></tr>"#, e.qualified_name, e.file_path, e.line_end - e.line_start + 1)).collect();
    let functions_html: String = functions.iter().take(100).map(|e| format!(r#"<tr><td><span class="badge badge-function">function</span></td><td><code>{}</code></td><td>{}</td><td>{}</td></tr>"#, e.qualified_name, e.file_path, e.line_end - e.line_start + 1)).collect();
    let classes_html: String = classes.iter().map(|e| format!(r#"<tr><td><span class="badge badge-class">class</span></td><td><code>{}</code></td><td>{}</td><td>{}</td></tr>"#, e.qualified_name, e.file_path, e.line_end - e.line_start + 1)).collect();

    let content = format!(
        r#"
        <div class="card">
            <h2>Search</h2>
            <input type="text" id="searchInput" placeholder="Search elements..." onkeyup="filterTable()">
        </div>
        <div class="card">
            <h2>Files ({})</h2>
            <table id="filesTable"><thead><tr><th>Type</th><th>Name</th><th>File</th><th>Lines</th></tr></thead><tbody>{}</tbody></table>
        </div>
        <div class="card">
            <h2>Functions ({})</h2>
            <table id="functionsTable"><thead><tr><th>Type</th><th>Name</th><th>File</th><th>Lines</th></tr></thead><tbody>{}</tbody></table>
        </div>
        <div class="card">
            <h2>Classes ({})</h2>
            <table id="classesTable"><thead><tr><th>Type</th><th>Name</th><th>File</th><th>Lines</th></tr></thead><tbody>{}</tbody></table>
        </div>
        <script>
            function filterTable() {{ const input = document.getElementById('searchInput').value.toLowerCase(); ['filesTable', 'functionsTable', 'classesTable'].forEach(id => {{ const t = document.getElementById(id); if (!t) return; [...t.rows].slice(1).forEach(r => r.style.display = r.textContent.toLowerCase().includes(input) ? '' : 'none'); }}); }}
        </script>"#,
        files.len(),
        files_html,
        functions.len(),
        functions_html,
        classes.len(),
        classes_html
    );

    axum::response::Html(base_html("Code Browser", &content))
}

#[allow(dead_code)]
pub async fn docs() -> axum::response::Html<String> {
    let content = r#"
        <div class="card">
            <h2>Documentation Viewer</h2>
            <p style="color: #666;">View generated documentation for your codebase.</p>
        </div>
        <div class="card">
            <h2>Available Documentation</h2>
            <div style="padding: 20px; background: #f5f5f5; border-radius: 8px; margin-bottom: 10px;">
                <h3>AGENTS.md</h3>
                <p style="color: #666;">Codebase context documentation for AI assistants</p>
            </div>
            <div style="padding: 20px; background: #f5f5f5; border-radius: 8px;">
                <h3>CLAUDE.md</h3>
                <p style="color: #666;">Claude-specific context documentation</p>
            </div>
        </div>
        <div class="card">
            <p style="color: #666;">Generate documentation using: <code>leankg generate</code></p>
        </div>"#;

    axum::response::Html(base_html("Documentation", content))
}

#[allow(dead_code)]
pub async fn annotate(State(state): State<AppState>) -> axum::response::Html<String> {
    let elements: Vec<_> = match state.get_graph_engine().await {
        Ok(g) => g.all_elements().unwrap_or_default(),
        Err(_) => vec![],
    };
    let annotations: Vec<_> = match state.get_graph_engine().await {
        Ok(g) => g.all_annotations().unwrap_or_default(),
        Err(_) => vec![],
    };

    let element_options: String = elements
        .iter()
        .map(|e| {
            format!(
                r#"<option value="{}">{} ({} - {})</option>"#,
                e.qualified_name, e.qualified_name, e.element_type, e.file_path
            )
        })
        .collect();
    let annotations_html: String = annotations
        .iter()
        .map(|a| {
            format!(
                r#"<tr><td><code>{}</code></td><td>{}</td><td>{}</td><td>{}</td></tr>"#,
                a.element_qualified,
                a.description,
                a.user_story_id.as_deref().unwrap_or("-"),
                a.feature_id.as_deref().unwrap_or("-")
            )
        })
        .collect();

    let content = format!(
        r#"
        <div class="card">
            <h2>Add Annotation</h2>
            <form id="annotationForm" onsubmit="submitAnnotation(event)">
                <div class="form-group"><label>Code Element</label><select id="elementSelect" required><option value="">Select...</option>{}</select></div>
                <div class="form-group"><label>Description</label><textarea id="descriptionInput" rows="4" required></textarea></div>
                <div class="form-group"><label>User Story ID</label><input type="text" id="userStoryInput" placeholder="US-123"></div>
                <div class="form-group"><label>Feature ID</label><input type="text" id="featureInput" placeholder="FEAT-AUTH"></div>
                <button type="submit">Save</button>
            </form>
            <div id="formMessage"></div>
        </div>
        <div class="card">
            <h2>Existing Annotations ({})</h2>
            <table><thead><tr><th>Element</th><th>Description</th><th>User Story</th><th>Feature</th></tr></thead><tbody>{}</tbody></table>
        </div>
        <script>
            async function submitAnnotation(e) {{ e.preventDefault(); const d = {{ element_qualified: document.getElementById('elementSelect').value, description: document.getElementById('descriptionInput').value, user_story_id: document.getElementById('userStoryInput').value || null, feature_id: document.getElementById('featureInput').value || null }}; try {{ const r = await fetch('/api/annotations', {{ method: 'POST', headers: {{ 'Content-Type': 'application/json' }}, body: JSON.stringify(d) }}); const res = await r.json(); document.getElementById('formMessage').innerHTML = res.success ? '<div class="success">Saved!</div>' : '<div class="error">' + (res.error || 'Error') + '</div>'; if (res.success) setTimeout(() => location.reload(), 1000); }} catch (err) {{ document.getElementById('formMessage').innerHTML = '<div class="error">' + err.message + '</div>'; }} }}
        </script>"#,
        element_options,
        annotations.len(),
        annotations_html
    );

    axum::response::Html(base_html("Annotate", &content))
}

#[allow(dead_code)]
pub async fn quality() -> axum::response::Html<String> {
    let content = r#"
        <div class="card">
            <h2>Code Quality Metrics</h2>
            <p style="color: #666;">Analyze code quality and identify potential issues.</p>
        </div>
        <div class="card">
            <h2>Quality Checks</h2>
            <div style="padding: 20px; background: #f5f5f5; border-radius: 8px; margin-bottom: 15px;">
                <h3>Large Functions</h3>
                <p style="color: #666;">Functions exceeding 50 lines may benefit from refactoring.</p>
                <code>leankg quality --min-lines 50</code>
            </div>
            <div style="padding: 20px; background: #f5f5f5; border-radius: 8px;">
                <h3>Language Filter</h3>
                <p style="color: #666;">Filter by programming language.</p>
                <code>leankg quality --lang go</code>
            </div>
        </div>"#;

    axum::response::Html(base_html("Code Quality", content))
}

#[allow(dead_code)]
pub async fn export_page() -> axum::response::Html<String> {
    let content = r#"
        <div class="card">
            <h2>Export Graph Data</h2>
            <p style="color: #666;">Download the code dependency graph data for external visualization.</p>
            <button onclick="exportJSON()">Export as JSON</button>
            <div id="exportStatus" style="margin-top: 15px;"></div>
        </div>
        <div class="card">
            <h2>Export Instructions</h2>
            <p style="color: #666;">The JSON export contains all graph data (nodes and edges) that can be visualized using D3.js or similar libraries.</p>
            <p style="color: #666; margin-top: 10px;">Use the /api/export/graph endpoint to fetch data programmatically.</p>
        </div>
        <script>
            function exportJSON() {
                const status = document.getElementById('exportStatus');
                status.innerHTML = '<div class="loading">Generating...</div>';
                fetch('/api/export/graph')
                    .then(r => r.json())
                    .then(d => {
                        if (d.success && d.data) {
                            const blob = new Blob([JSON.stringify(d.data, null, 2)], { type: 'application/json' });
                            const url = URL.createObjectURL(blob);
                            const a = document.createElement('a');
                            a.href = url;
                            a.download = 'leankg-graph.json';
                            a.click();
                            URL.revokeObjectURL(url);
                            status.innerHTML = '<div class="success">Export complete!</div>';
                        } else {
                            status.innerHTML = '<div class="error">No data. Index first.</div>';
                        }
                    })
                    .catch(e => { status.innerHTML = '<div class="error">Error: ' + e.message + '</div>'; });
            }
        </script>"#;

    axum::response::Html(base_html("Export", content))
}

#[allow(dead_code)]
pub async fn settings() -> axum::response::Html<String> {
    let content = r#"
        <div class="card">
            <h2>Settings</h2>
            <p style="color: #666;">Configure your LeanKG settings.</p>
        </div>
        <div class="card">
            <h2>Project Configuration</h2>
            <div class="form-group"><label>Database Path</label><code>.leankg/</code></div>
            <div class="form-group"><label>Index Path</label><code>./src</code></div>
        </div>
        <div class="card">
            <h2>About</h2>
            <p style="color: #666;">LeanKG - Lightweight knowledge graph for AI-assisted development.</p>
            <p style="color: #666; margin-top: 10px;">Version: 0.1.0</p>
        </div>"#;

    axum::response::Html(base_html("Settings", content))
}

#[allow(dead_code)]
pub async fn api_elements(State(state): State<AppState>) -> impl IntoResponse {
    let result: Result<Vec<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.all_elements().map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    match result {
        Ok(elements) => ApiResponse {
            success: true,
            data: Some(elements),
            error: None,
        },
        Err(e) => ApiResponse {
            success: false,
            data: None,
            error: Some(e),
        },
    }
}

#[allow(dead_code)]
pub async fn api_relationships(State(state): State<AppState>) -> impl IntoResponse {
    let result: Result<Vec<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.all_relationships().map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    match result {
        Ok(rels) => ApiResponse {
            success: true,
            data: Some(rels),
            error: None,
        },
        Err(e) => ApiResponse {
            success: false,
            data: None,
            error: Some(e),
        },
    }
}

#[allow(dead_code)]
pub async fn api_annotations(State(state): State<AppState>) -> impl IntoResponse {
    let result: Result<Vec<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.all_annotations().map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    match result {
        Ok(anns) => ApiResponse {
            success: true,
            data: Some(anns),
            error: None,
        },
        Err(e) => ApiResponse {
            success: false,
            data: None,
            error: Some(e),
        },
    }
}

#[allow(dead_code)]
pub async fn api_create_annotation(
    State(state): State<AppState>,
    Json(req): Json<AnnotationRequest>,
) -> impl IntoResponse {
    let db = match state.get_db() {
        Ok(db) => db,
        Err(e) => {
            return ApiResponse {
                success: false,
                data: None,
                error: Some(e.to_string()),
            }
        }
    };
    let result = db::create_business_logic(
        &db,
        &req.element_qualified,
        &req.description,
        req.user_story_id.as_deref(),
        req.feature_id.as_deref(),
    );
    match result {
        Ok(bl) => ApiResponse {
            success: true,
            data: Some(bl),
            error: None,
        },
        Err(e) => ApiResponse {
            success: false,
            data: None,
            error: Some(e.to_string()),
        },
    }
}

#[allow(dead_code)]
pub async fn api_get_annotation(
    State(state): State<AppState>,
    Path(element): Path<String>,
) -> impl IntoResponse {
    let result: Result<Option<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.get_annotation(&element).map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    match result {
        Ok(ann) => ApiResponse {
            success: true,
            data: ann,
            error: None,
        },
        Err(e) => ApiResponse {
            success: false,
            data: None,
            error: Some(e),
        },
    }
}

#[allow(dead_code)]
pub async fn api_update_annotation(
    State(state): State<AppState>,
    Path(_element): Path<String>,
    Json(req): Json<AnnotationRequest>,
) -> impl IntoResponse {
    let db = match state.get_db() {
        Ok(db) => db,
        Err(e) => {
            return ApiResponse {
                success: false,
                data: None,
                error: Some(e.to_string()),
            }
        }
    };
    let result = db::update_business_logic(
        &db,
        &req.element_qualified,
        &req.description,
        req.user_story_id.as_deref(),
        req.feature_id.as_deref(),
    );
    match result {
        Ok(bl) => ApiResponse {
            success: true,
            data: bl,
            error: None,
        },
        Err(e) => ApiResponse {
            success: false,
            data: None,
            error: Some(e.to_string()),
        },
    }
}

#[allow(dead_code)]
pub async fn api_search(
    State(state): State<AppState>,
    Query(params): Query<SearchParams>,
) -> impl IntoResponse {
    let elements_result: Result<Vec<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.all_elements().map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    let elements = match elements_result {
        Ok(e) => e,
        Err(e) => {
            return ApiResponse {
                success: false,
                data: None,
                error: Some(e.to_string()),
            }
        }
    };
    let mut filtered: Vec<_> = elements.iter().collect();
    if let Some(ref q) = params.q {
        let ql = q.to_lowercase();
        filtered.retain(|e| {
            e.qualified_name.to_lowercase().contains(&ql)
                || e.name.to_lowercase().contains(&ql)
                || e.file_path.to_lowercase().contains(&ql)
        });
    }
    if let Some(ref et) = params.element_type {
        filtered.retain(|e| e.element_type == *et);
    }
    if let Some(ref fp) = params.file_path {
        filtered.retain(|e| e.file_path.contains(fp));
    }
    let result: Vec<_> = filtered.into_iter().cloned().collect();
    ApiResponse {
        success: true,
        data: Some(result),
        error: None,
    }
}

#[allow(dead_code)]
pub async fn api_graph_data(State(state): State<AppState>) -> impl IntoResponse {
    let elements_result: Result<Vec<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.all_elements().map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    let relationships_result: Result<Vec<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.all_relationships().map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    match (elements_result, relationships_result) {
        (Ok(elements), Ok(relationships)) => {
            let nodes: Vec<GraphNode> = elements
                .iter()
                .map(|e| GraphNode {
                    id: e.qualified_name.clone(),
                    label: e.name.clone(),
                    element_type: e.element_type.clone(),
                    file_path: e.file_path.clone(),
                })
                .collect();
            let edges: Vec<GraphEdge> = relationships
                .iter()
                .map(|r| GraphEdge {
                    source: r.source_qualified.clone(),
                    target: r.target_qualified.clone(),
                    rel_type: r.rel_type.clone(),
                })
                .collect();
            ApiResponse {
                success: true,
                data: Some(GraphData { nodes, edges }),
                error: None,
            }
        }
        (Err(e), _) | (_, Err(e)) => ApiResponse {
            success: false,
            data: None,
            error: Some(e),
        },
    }
}

#[allow(dead_code)]
pub async fn api_export_graph(State(state): State<AppState>) -> impl IntoResponse {
    let elements_result: Result<Vec<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.all_elements().map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    let relationships_result: Result<Vec<_>, String> = match state.get_graph_engine().await {
        Ok(g) => g.all_relationships().map_err(|e| e.to_string()),
        Err(e) => Err(e.to_string()),
    };
    match (elements_result, relationships_result) {
        (Ok(elements), Ok(relationships)) => {
            let nodes: Vec<GraphNode> = elements
                .iter()
                .map(|e| GraphNode {
                    id: e.qualified_name.clone(),
                    label: e.name.clone(),
                    element_type: e.element_type.clone(),
                    file_path: e.file_path.clone(),
                })
                .collect();
            let edges: Vec<GraphEdge> = relationships
                .iter()
                .map(|r| GraphEdge {
                    source: r.source_qualified.clone(),
                    target: r.target_qualified.clone(),
                    rel_type: r.rel_type.clone(),
                })
                .collect();
            ApiResponse {
                success: true,
                data: Some(GraphData { nodes, edges }),
                error: None,
            }
        }
        (Err(e), _) | (_, Err(e)) => ApiResponse {
            success: false,
            data: None,
            error: Some(e),
        },
    }
}

#[allow(dead_code)]
pub async fn api_query(
    axum::extract::Json(_req): axum::extract::Json<QueryRequest>,
) -> Result<axum::extract::Json<QueryResponse>, (StatusCode, &'static str)> {
    Ok(axum::extract::Json(QueryResponse { result: vec![] }))
}
