use diagnostics::DiagnosticSink;
use stdlib::LIS_PRELUDE_SOURCE;
use syntax::program::{File, Visibility};

use crate::call_classification::compute_module_ufcs;
use crate::checker::Checker;
use crate::store::Store;

pub const PRELUDE_MODULE_ID: &str = "prelude";
pub const PRELUDE_FILE_ID: u32 = 1;

pub fn parse_and_register_prelude(store: &mut Store, sink: &DiagnosticSink) {
    let result = syntax::build_ast(LIS_PRELUDE_SOURCE, PRELUDE_FILE_ID);

    sink.extend_parse_errors(result.errors);

    store.mark_visited(PRELUDE_MODULE_ID);
    store.store_file(
        PRELUDE_MODULE_ID,
        File {
            id: PRELUDE_FILE_ID,
            module_id: PRELUDE_MODULE_ID.to_string(),
            name: "prelude.d.lis".to_string(),
            source: LIS_PRELUDE_SOURCE.to_string(),
            items: result.ast,
        },
    );

    let mut checker = Checker::new(store, sink);
    checker.cursor.module_id = PRELUDE_MODULE_ID.to_string();
    checker.cursor.file_id = Some(PRELUDE_FILE_ID);

    let module = checker
        .store
        .get_module(PRELUDE_MODULE_ID)
        .cloned()
        .expect("prelude module must exist");

    for file in module.all_typedefs() {
        checker.register_type_names(&file.items, &Visibility::Public);
    }

    checker.reset_scopes();
    checker.put_unprefixed_module_in_scope(PRELUDE_MODULE_ID);

    for file in module.all_typedefs() {
        checker.register_types(&file.items);
        checker.register_values(&file.items, &Visibility::Public);
    }

    checker.cursor.file_id = None;
}

pub fn compute_prelude_ufcs(store: &Store) -> Vec<(String, String)> {
    let module = store
        .get_module(PRELUDE_MODULE_ID)
        .expect("prelude must exist");
    compute_module_ufcs(module, PRELUDE_MODULE_ID)
}
