use super::*;

fn setup_db() -> Connection {
    let conn = Connection::open_in_memory().unwrap();
    conn.execute_batch(
        "
        CREATE TABLE projects (
            id INTEGER PRIMARY KEY,
            gitlab_project_id INTEGER UNIQUE NOT NULL,
            path_with_namespace TEXT NOT NULL,
            default_branch TEXT,
            web_url TEXT,
            created_at INTEGER,
            updated_at INTEGER,
            raw_payload_id INTEGER
        );
        CREATE INDEX idx_projects_path ON projects(path_with_namespace);
    ",
    )
    .unwrap();
    conn
}

fn insert_project(conn: &Connection, id: i64, path: &str) {
    conn.execute(
        "INSERT INTO projects (id, gitlab_project_id, path_with_namespace) VALUES (?1, ?2, ?3)",
        rusqlite::params![id, id * 100, path],
    )
    .unwrap();
}

#[test]
fn test_exact_match() {
    let conn = setup_db();
    insert_project(&conn, 1, "backend/auth-service");
    let id = resolve_project(&conn, "backend/auth-service").unwrap();
    assert_eq!(id, 1);
}

#[test]
fn test_case_insensitive() {
    let conn = setup_db();
    insert_project(&conn, 1, "backend/auth-service");
    let id = resolve_project(&conn, "Backend/Auth-Service").unwrap();
    assert_eq!(id, 1);
}

#[test]
fn test_suffix_unambiguous() {
    let conn = setup_db();
    insert_project(&conn, 1, "backend/auth-service");
    insert_project(&conn, 2, "frontend/web-ui");
    let id = resolve_project(&conn, "auth-service").unwrap();
    assert_eq!(id, 1);
}

#[test]
fn test_suffix_ambiguous() {
    let conn = setup_db();
    insert_project(&conn, 1, "backend/auth-service");
    insert_project(&conn, 2, "frontend/auth-service");
    let err = resolve_project(&conn, "auth-service").unwrap_err();
    let msg = err.to_string();
    assert!(
        msg.contains("ambiguous"),
        "Expected ambiguous error, got: {}",
        msg
    );
    assert!(msg.contains("backend/auth-service"));
    assert!(msg.contains("frontend/auth-service"));
}

#[test]
fn test_substring_unambiguous() {
    let conn = setup_db();
    insert_project(&conn, 1, "vs/python-code");
    insert_project(&conn, 2, "vs/typescript-code");
    let id = resolve_project(&conn, "typescript").unwrap();
    assert_eq!(id, 2);
}

#[test]
fn test_substring_case_insensitive() {
    let conn = setup_db();
    insert_project(&conn, 1, "vs/python-code");
    insert_project(&conn, 2, "vs/typescript-code");
    let id = resolve_project(&conn, "TypeScript").unwrap();
    assert_eq!(id, 2);
}

#[test]
fn test_substring_ambiguous() {
    let conn = setup_db();
    insert_project(&conn, 1, "vs/python-code");
    insert_project(&conn, 2, "vs/typescript-code");
    let err = resolve_project(&conn, "code").unwrap_err();
    let msg = err.to_string();
    assert!(
        msg.contains("ambiguous"),
        "Expected ambiguous error, got: {}",
        msg
    );
    assert!(msg.contains("vs/python-code"));
    assert!(msg.contains("vs/typescript-code"));
}

#[test]
fn test_suffix_preferred_over_substring() {
    let conn = setup_db();
    insert_project(&conn, 1, "backend/auth-service");
    insert_project(&conn, 2, "backend/auth-service-v2");
    let id = resolve_project(&conn, "auth-service").unwrap();
    assert_eq!(id, 1);
}

#[test]
fn test_no_match() {
    let conn = setup_db();
    insert_project(&conn, 1, "backend/auth-service");
    let err = resolve_project(&conn, "nonexistent").unwrap_err();
    let msg = err.to_string();
    assert!(
        msg.contains("not found"),
        "Expected not found error, got: {}",
        msg
    );
    assert!(msg.contains("backend/auth-service"));
}

#[test]
fn test_empty_projects() {
    let conn = setup_db();
    let err = resolve_project(&conn, "anything").unwrap_err();
    let msg = err.to_string();
    assert!(msg.contains("No projects have been synced"));
}

#[test]
fn test_underscore_not_wildcard() {
    let conn = setup_db();
    insert_project(&conn, 1, "backend/my_project");
    insert_project(&conn, 2, "backend/my-project");
    // `_` in user input must not match `-` (LIKE wildcard behavior)
    let id = resolve_project(&conn, "my_project").unwrap();
    assert_eq!(id, 1);
}

#[test]
fn test_percent_not_wildcard() {
    let conn = setup_db();
    insert_project(&conn, 1, "backend/a%b");
    insert_project(&conn, 2, "backend/axyzb");
    // `%` in user input must not match arbitrary strings
    let id = resolve_project(&conn, "a%b").unwrap();
    assert_eq!(id, 1);
}

#[test]
fn test_lookup_by_gitlab_project_id() {
    use crate::test_support::{insert_project as insert_proj, setup_test_db};

    let conn = setup_test_db();
    insert_proj(&conn, 1, "team/alpha");
    insert_proj(&conn, 2, "team/beta");

    // insert_project sets gitlab_project_id = id * 100
    let path: String = conn
        .query_row(
            "SELECT path_with_namespace FROM projects
             WHERE gitlab_project_id = ?1
             ORDER BY id LIMIT 1",
            rusqlite::params![200_i64],
            |row| row.get(0),
        )
        .unwrap();

    assert_eq!(path, "team/beta");
}
