//! Autocomplete/completion provider
//!
//! Provides context-aware completion suggestions for:
//! - Keywords (filtered by context)
//! - Entity names (characters, templates, etc.)
//! - Field names (from templates/species when in character block)
//! - Type names (templates/species when after ':')
//! - Enum values
//! - Action names (in behavior trees)

use tower_lsp::lsp_types::{
    CompletionItem,
    CompletionItemKind,
    CompletionList,
    CompletionParams,
    CompletionResponse,
    Documentation,
    MarkupContent,
    MarkupKind,
};

use super::document::Document;
use crate::syntax::ast::Value;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum CompletionContext {
    /// Top-level of the document
    TopLevel,
    /// Inside a character/template field block
    InFieldBlock,
    /// After a colon (expecting a type or value)
    AfterColon,
    /// Inside a behavior tree
    InBehavior,
    /// Inside a life arc
    InLifeArc,
    /// Inside a relationship
    InRelationship,
    /// Unknown context
    Unknown,
}

/// Get completion items at a position
pub fn get_completions(doc: &Document, params: &CompletionParams) -> Option<CompletionResponse> {
    let position = params.text_document_position.position;

    // Check for field accessor using the specialized function
    // It will return Some only if there's an identifier followed by a dot
    if let Some(field_items) = get_field_accessor_completions(doc, position) {
        return Some(CompletionResponse::List(CompletionList {
            is_incomplete: false,
            items: field_items,
        }));
    }

    // Convert position to byte offset for context-based completions
    let offset = position_to_offset(doc, position.line as usize, position.character as usize)?;

    // Check if we're typing a new identifier name after a declaration keyword
    if is_typing_declaration_name(&doc.text, offset) {
        // Don't show completions when typing a new identifier
        return None;
    }

    // Determine context by analyzing text around cursor
    let context = determine_context(&doc.text, offset);

    let mut items = Vec::new();

    match context {
        | CompletionContext::TopLevel => {
            // At top level, suggest declaration keywords
            items.extend(top_level_keyword_completions());
            // Also suggest existing entity names for reference
            items.extend(entity_completions(doc));
        },
        | CompletionContext::InFieldBlock => {
            // Always include generic field keywords (age, bond, from, etc.)
            items.extend(field_keyword_completions());
            // Also include contextual species/template fields if available
            if let Some(species_fields) = get_contextual_field_completions(doc, offset) {
                items.extend(species_fields);
            }
        },
        | CompletionContext::AfterColon => {
            // After colon, suggest types (templates, species)
            items.extend(type_completions(doc));
        },
        | CompletionContext::InBehavior => {
            // In behavior tree, suggest behavior-specific keywords
            items.extend(behavior_keyword_completions());
            items.extend(behavior_completions(doc)); // Reference to other
                                                     // behaviors
        },
        | CompletionContext::InLifeArc => {
            // In life arc, suggest state-related keywords
            items.extend(life_arc_keyword_completions());
        },
        | CompletionContext::InRelationship => {
            // In relationship, suggest relationship-specific keywords
            items.extend(relationship_keyword_completions());
            items.extend(character_completions(doc)); // For participants
        },
        | CompletionContext::Unknown => {
            // When context is unclear, provide all completions
            items.extend(all_keyword_completions());
            items.extend(entity_completions(doc));
        },
    }

    // Set sort_text for proper ordering: field accessors first (0xxx), then others
    // (1xxx)
    for item in &mut items {
        let detail = item.detail.as_deref().unwrap_or("");
        let is_field = detail.contains("field") || detail.contains("trait");

        // Field accessors get "0" prefix, others get "1" prefix
        let prefix = if is_field { "0" } else { "1" };
        item.sort_text = Some(format!("{}{}", prefix, item.label));
    }

    // Sort by sort_text for consistent ordering
    items.sort_by(|a, b| {
        let sort_a = a.sort_text.as_deref().unwrap_or(&a.label);
        let sort_b = b.sort_text.as_deref().unwrap_or(&b.label);
        sort_a.cmp(sort_b)
    });

    Some(CompletionResponse::Array(items))
}

/// Convert LSP position to byte offset
fn position_to_offset(doc: &Document, line: usize, character: usize) -> Option<usize> {
    let line_start = doc.positions.line_offset(line)?;
    Some(line_start + character)
}

/// Returns true if the token is a declaration keyword (character, behavior,
/// etc.)
fn is_declaration_keyword(token: &crate::syntax::lexer::Token) -> bool {
    use crate::syntax::lexer::Token;
    matches!(
        token,
        Token::Character |
            Token::Template |
            Token::Species |
            Token::Behavior |
            Token::LifeArc |
            Token::Relationship |
            Token::Institution |
            Token::Location |
            Token::Schedule
    )
}

/// Check if we're typing a new identifier name after a declaration keyword
fn is_typing_declaration_name(text: &str, offset: usize) -> bool {
    use crate::syntax::lexer::{
        Lexer,
        Token,
    };

    // Get text before cursor (up to 200 chars)
    let start = offset.saturating_sub(200);
    let before = &text[start..offset.min(text.len())];

    // Tokenize using lexer
    let lexer = Lexer::new(before);
    let tokens: Vec<_> = lexer.collect();

    // Check if the last token (or second-to-last if we just typed an identifier)
    // is a declaration keyword
    if !tokens.is_empty() {
        let last_idx = tokens.len() - 1;

        // Check last token — cursor is right after a declaration keyword
        if is_declaration_keyword(&tokens[last_idx].1) {
            return true;
        }

        // Check second-to-last token (in case we're in the middle of typing an
        // identifier after the keyword)
        if tokens.len() >= 2 {
            let second_last_idx = tokens.len() - 2;
            if is_declaration_keyword(&tokens[second_last_idx].1) {
                // Make sure the last token is an identifier (not a colon or brace)
                if let (_offset, Token::Ident(_), _end) = &tokens[last_idx] {
                    return true;
                }
            }
        }
    }

    false
}

/// Format a value as its type string for documentation
fn format_value_type(value: &Value) -> String {
    match value {
        | Value::Identifier(path) => path.join("."),
        | Value::Text(_) => "Text".to_string(),
        | Value::Number(_) => "Number".to_string(),
        | Value::Decimal(_) => "Decimal".to_string(),
        | Value::Boolean(_) => "Boolean".to_string(),
        | Value::List(items) => {
            if items.is_empty() {
                "List".to_string()
            } else {
                format!("[{}]", format_value_type(&items[0]))
            }
        },
        | Value::Object(_) => "Object".to_string(),
        | Value::Range(start, end) => {
            format!("{}..{}", format_value_type(start), format_value_type(end))
        },
        | Value::Time(_) => "Time".to_string(),
        | Value::Duration(_) => "Duration".to_string(),
        | Value::ProseBlock(_) => "ProseBlock".to_string(),
        | Value::Override(_) => "Override".to_string(),
        | Value::Any => "Any".to_string(),
    }
}

/// Get field completions based on the current character/template context
fn get_contextual_field_completions(doc: &Document, offset: usize) -> Option<Vec<CompletionItem>> {
    use crate::{
        resolve::names::DeclKind,
        syntax::ast::Declaration,
    };

    let ast = doc.ast.as_ref()?;

    // Find which declaration contains the cursor offset
    for decl in &ast.declarations {
        match decl {
            | Declaration::Character(character) => {
                // Check if cursor is inside this character block
                if offset >= character.span.start && offset <= character.span.end {
                    let mut items = Vec::new();

                    // Add special keywords
                    items.push(simple_item(
                        "from",
                        "Apply a template",
                        "from ${1:TemplateName}",
                    ));
                    items.push(simple_item(
                        "include",
                        "Include a template",
                        "include ${1:TemplateName}",
                    ));

                    // Add fields from species
                    if let Some(ref species_name) = character.species {
                        if let Some(species_entry) = doc.name_table.resolve_name(species_name) {
                            if species_entry.kind == DeclKind::Species {
                                for species_decl in &ast.declarations {
                                    if let Declaration::Species(species) = species_decl {
                                        if &species.name == species_name {
                                            for field in &species.fields {
                                                items.push(CompletionItem {
                                                    label: format!("{}:", field.name),
                                                    kind: Some(CompletionItemKind::FIELD),
                                                    detail: Some(format!("({})", species_name)),
                                                    insert_text: Some(format!("{}: $0", field.name)),
                                                    insert_text_format: Some(tower_lsp::lsp_types::InsertTextFormat::SNIPPET),
                                                    ..Default::default()
                                                });
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    return Some(items);
                }
            },
            | Declaration::Template(template) => {
                // Check if cursor is inside this template block
                if offset >= template.span.start && offset <= template.span.end {
                    // Templates can suggest common field patterns
                    return Some(vec![simple_item(
                        "include",
                        "Include a template",
                        "include ${1:TemplateName}",
                    )]);
                }
            },
            | _ => {},
        }
    }

    None
}

/// Get field completions when triggered by `.` using lexer
fn get_field_accessor_completions(
    doc: &Document,
    position: tower_lsp::lsp_types::Position,
) -> Option<Vec<CompletionItem>> {
    use crate::{
        resolve::names::DeclKind,
        syntax::{
            ast::Declaration,
            lexer::{
                Lexer,
                Token,
            },
        },
    };

    // Lex the line up to the cursor to find the identifier before the dot
    let line_offset = doc.positions.line_offset(position.line as usize)?;
    let line_end = (line_offset + position.character as usize).min(doc.text.len());
    let line_text = &doc.text[line_offset..line_end];

    // Lex tokens on this line
    let lexer = Lexer::new(line_text);
    let tokens: Vec<_> = lexer.collect();

    // Check if there's a dot token - if not, this isn't a field accessor
    let has_dot = tokens
        .iter()
        .any(|(_, token, _)| matches!(token, Token::Dot));
    if !has_dot {
        return None;
    }

    // Find the last identifier before the last dot
    let mut last_ident = None;
    for (_start, token, _end) in &tokens {
        match token {
            | Token::Ident(name) => last_ident = Some(name.clone()),
            | Token::Dot => {
                // We found a dot - if we have an identifier, that's our target
                if last_ident.is_some() {
                    break;
                }
            },
            | _ => {},
        }
    }

    // If there's a dot but no identifier, return empty list to block keywords
    let identifier = match last_ident {
        | Some(id) => id,
        | None => return Some(Vec::new()),
    };

    // Look up the identifier - if it fails, still return empty to block keywords
    let entry = match doc.name_table.resolve_name(&identifier) {
        | Some(e) => e,
        | None => return Some(Vec::new()),
    };
    let ast = match doc.ast.as_ref() {
        | Some(a) => a,
        | None => return Some(Vec::new()),
    };

    let mut items = Vec::new();

    match entry.kind {
        | DeclKind::Character => {
            for decl in &ast.declarations {
                if let Declaration::Character(character) = decl {
                    if character.name == identifier {
                        // Add character's own fields
                        for field in &character.fields {
                            let value_type = format_value_type(&field.value);
                            items.push(CompletionItem {
                                label: field.name.clone(),
                                kind: Some(CompletionItemKind::FIELD),
                                detail: None, // Keep inline display clean
                                documentation: Some(Documentation::MarkupContent(MarkupContent {
                                    kind: MarkupKind::Markdown,
                                    value: format!(
                                        "**Field** of `{}`\n\nType: `{}`",
                                        identifier, value_type
                                    ),
                                })),
                                ..Default::default()
                            });
                        }

                        // Add species fields
                        if let Some(ref species_name) = character.species {
                            if let Some(species_entry) = doc.name_table.resolve_name(species_name) {
                                if species_entry.kind == DeclKind::Species {
                                    for decl in &ast.declarations {
                                        if let Declaration::Species(species) = decl {
                                            if &species.name == species_name {
                                                for field in &species.fields {
                                                    let value_type =
                                                        format_value_type(&field.value);
                                                    items.push(CompletionItem {
                                                        label: field.name.clone(),
                                                        kind: Some(CompletionItemKind::FIELD),
                                                        detail: Some(format!("({})", species_name)),
                                                        documentation: Some(Documentation::MarkupContent(MarkupContent {
                                                            kind: MarkupKind::Markdown,
                                                            value: format!("**Trait** from `{}`\n\nType: `{}`", species_name, value_type),
                                                        })),
                                                        ..Default::default()
                                                    });
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        // Add template fields
                        if let Some(ref template_names) = character.template {
                            for template_name in template_names {
                                if let Some(template_entry) =
                                    doc.name_table.resolve_name(template_name)
                                {
                                    if template_entry.kind == DeclKind::Template {
                                        for decl in &ast.declarations {
                                            if let Declaration::Template(template) = decl {
                                                if &template.name == template_name {
                                                    for field in &template.fields {
                                                        let value_type =
                                                            format_value_type(&field.value);
                                                        items.push(CompletionItem {
                                                            label: field.name.clone(),
                                                            kind: Some(CompletionItemKind::FIELD),
                                                            detail: Some(format!("({})", template_name)),
                                                            documentation: Some(Documentation::MarkupContent(MarkupContent {
                                                                kind: MarkupKind::Markdown,
                                                                value: format!("**Template field** from `{}`\n\nType: `{}`", template_name, value_type),
                                                            })),
                                                            ..Default::default()
                                                        });
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        break;
                    }
                }
            }
        },
        // For non-character declarations, still return empty list to block keywords
        | _ => return Some(Vec::new()),
    }

    // Always return Some to block keyword completions, even if no fields found
    items.sort_by(|a, b| a.label.cmp(&b.label));
    Some(items)
}

/// Determine completion context by analyzing tokens around cursor using lexer
fn determine_context(text: &str, offset: usize) -> CompletionContext {
    use crate::syntax::lexer::{
        Lexer,
        Token,
    };

    // Get text before cursor (up to 500 chars for context)
    let start = offset.saturating_sub(500);
    let before = &text[start..offset.min(text.len())];

    // Tokenize using lexer
    let lexer = Lexer::new(before);
    let tokens: Vec<_> = lexer.collect();

    // Track state by analyzing tokens
    let mut nesting_level: i32 = 0;
    let mut last_context: Option<CompletionContext> = None;
    let mut seen_colon_without_brace = false;

    for (_offset, token, _end) in &tokens {
        match token {
            | Token::LBrace => {
                nesting_level += 1;
                seen_colon_without_brace = false;
            },
            | Token::RBrace => nesting_level = nesting_level.saturating_sub(1),
            | Token::Colon => seen_colon_without_brace = true,
            | Token::Behavior => {
                last_context = Some(CompletionContext::InBehavior);
                seen_colon_without_brace = false;
            },
            | Token::LifeArc => {
                last_context = Some(CompletionContext::InLifeArc);
                seen_colon_without_brace = false;
            },
            | Token::Relationship => {
                last_context = Some(CompletionContext::InRelationship);
                seen_colon_without_brace = false;
            },
            | Token::Character |
            Token::Template |
            Token::Species |
            Token::Institution |
            Token::Location |
            Token::Schedule => {
                last_context = Some(CompletionContext::InFieldBlock);
                seen_colon_without_brace = false;
            },
            | _ => {},
        }
    }

    // If we saw a colon without a brace after it, we're in type position
    if seen_colon_without_brace {
        return CompletionContext::AfterColon;
    }

    // At top level if no nesting
    if nesting_level == 0 {
        return CompletionContext::TopLevel;
    }

    last_context.unwrap_or(CompletionContext::Unknown)
}

/// Get entity completions (all symbols)
fn entity_completions(doc: &Document) -> Vec<CompletionItem> {
    use crate::resolve::names::DeclKind;

    let mut items = Vec::new();

    for entry in doc.name_table.all_entries() {
        let kind = match entry.kind {
            | DeclKind::Character => CompletionItemKind::CLASS,
            | DeclKind::Template => CompletionItemKind::INTERFACE,
            | DeclKind::LifeArc => CompletionItemKind::FUNCTION,
            | DeclKind::Schedule => CompletionItemKind::EVENT,
            | DeclKind::Behavior => CompletionItemKind::MODULE,
            | DeclKind::Institution => CompletionItemKind::MODULE,
            | DeclKind::Relationship => CompletionItemKind::STRUCT,
            | DeclKind::Location => CompletionItemKind::CONSTANT,
            | DeclKind::Species => CompletionItemKind::CLASS,
        };

        let name = entry
            .qualified_path
            .last()
            .unwrap_or(&String::new())
            .clone();

        items.push(CompletionItem {
            label: name,
            kind: Some(kind),
            detail: Some(format!("{:?}", entry.kind)),
            ..Default::default()
        });
    }

    items
}

/// Get type completions (templates and species)
fn type_completions(doc: &Document) -> Vec<CompletionItem> {
    use crate::resolve::names::DeclKind;

    let mut items = Vec::new();

    for entry in doc.name_table.all_entries() {
        match entry.kind {
            | DeclKind::Template | DeclKind::Species => {
                let name = entry
                    .qualified_path
                    .last()
                    .unwrap_or(&String::new())
                    .clone();
                items.push(CompletionItem {
                    label: name,
                    kind: Some(CompletionItemKind::INTERFACE),
                    detail: Some(format!("{:?}", entry.kind)),
                    documentation: Some(Documentation::String("Type annotation".to_string())),
                    ..Default::default()
                });
            },
            | _ => {},
        }
    }

    items
}

/// Get behavior completions
fn behavior_completions(doc: &Document) -> Vec<CompletionItem> {
    use crate::resolve::names::DeclKind;

    let mut items = Vec::new();

    for entry in doc.name_table.entries_of_kind(DeclKind::Behavior) {
        let name = entry
            .qualified_path
            .last()
            .unwrap_or(&String::new())
            .clone();
        items.push(CompletionItem {
            label: format!("@{}", name),
            kind: Some(CompletionItemKind::REFERENCE),
            detail: Some("Behavior tree reference".to_string()),
            insert_text: Some(format!("@{}", name)),
            ..Default::default()
        });
    }

    items
}

/// Get character completions
fn character_completions(doc: &Document) -> Vec<CompletionItem> {
    use crate::resolve::names::DeclKind;

    let mut items = Vec::new();

    for entry in doc.name_table.entries_of_kind(DeclKind::Character) {
        let name = entry
            .qualified_path
            .last()
            .unwrap_or(&String::new())
            .clone();
        items.push(CompletionItem {
            label: name,
            kind: Some(CompletionItemKind::CLASS),
            detail: Some("Character".to_string()),
            ..Default::default()
        });
    }

    items
}

/// Get all keyword completions (fallback)
fn all_keyword_completions() -> Vec<CompletionItem> {
    let mut items = top_level_keyword_completions();
    items.extend(field_keyword_completions());
    items.extend(behavior_keyword_completions());
    items.extend(life_arc_keyword_completions());
    items.extend(relationship_keyword_completions());
    items
}

/// Get top-level declaration keywords
fn top_level_keyword_completions() -> Vec<CompletionItem> {
    vec![
        keyword_item("character", "Define a character entity", "character ${1:Name}: ${2:Species} {\n    $0\n}"),
        keyword_item("template", "Define a reusable field template", "template ${1:Name} {\n    $0\n}"),
        keyword_item("life_arc", "Define a state machine", "life_arc ${1:Name} {\n    state ${2:initial} {\n        $0\n    }\n}"),
        keyword_item("schedule", "Define a daily schedule", "schedule ${1:Name} {\n    ${2:08:00} -> ${3:09:00}: ${4:block_name} {\n        $0\n    }\n}"),
        keyword_item("behavior", "Define a behavior tree", "behavior ${1:Name} {\n    $0\n}"),
        keyword_item("institution", "Define an organization", "institution ${1:Name} {\n    $0\n}"),
        keyword_item("relationship", "Define a relationship", "relationship ${1:Name} {\n    $0\n}"),
        keyword_item("location", "Define a location", "location ${1:Name} {\n    $0\n}"),
        keyword_item("species", "Define a species", "species ${1:Name} {\n    $0\n}"),
        keyword_item("use", "Import declarations", "use ${1:path::to::item};"),
        keyword_item("concept", "Define an algebraic data type", "concept ${1:Name};"),
        keyword_item("sub_concept", "Define a sub-type", "sub_concept ${1:Parent}.${2:Name} {\n    $0\n}"),
        keyword_item("definition", "Pattern match on concepts", "definition ${1:Name} {\n    $0\n}"),
    ]
}

/// Get field-level keywords
fn field_keyword_completions() -> Vec<CompletionItem> {
    vec![
        keyword_item("from", "Apply a template", "from ${1:TemplateName}"),
        keyword_item("include", "Include a template", "include ${1:TemplateName}"),
        keyword_item("strict", "Enforce strict template fields", "strict"),
        // Common field names
        simple_item("age", "Age field", "age: ${1:0}"),
        simple_item("name", "Name field", "name: \"${1:Name}\""),
        simple_item("bond", "Bond trait (0.0-1.0)", "bond: ${1:0.5}"),
        simple_item("trust", "Trust trait (0.0-1.0)", "trust: ${1:0.5}"),
        simple_item("love", "Love trait (0.0-1.0)", "love: ${1:0.5}"),
    ]
}

/// Get behavior tree keywords
fn behavior_keyword_completions() -> Vec<CompletionItem> {
    vec![
        // Symbolic syntax
        keyword_item(
            "?",
            "Selector node (try options in order)",
            "? {\n    $0\n}",
        ),
        keyword_item(">", "Sequence node (execute in order)", "> {\n    $0\n}"),
        keyword_item("*", "Repeat node (loop forever)", "* {\n    $0\n}"),
        simple_item("@", "Subtree reference", "@${1:behavior::name}"),
        // Word-based syntax
        keyword_item(
            "choose",
            "Selector — try options in order",
            "choose {\n    $0\n}",
        ),
        keyword_item("then", "Sequence — execute in order", "then {\n    $0\n}"),
        keyword_item("repeat", "Repeat node", "repeat {\n    $0\n}"),
        keyword_item(
            "if",
            "Conditional decorator",
            "if(${1:condition}) {\n    $0\n}",
        ),
        keyword_item("when", "Condition node", "when(${1:condition})"),
        keyword_item("invert", "Invert result", "invert {\n    $0\n}"),
        keyword_item("retry", "Retry decorator", "retry(${1:3}) {\n    $0\n}"),
        keyword_item(
            "timeout",
            "Timeout decorator",
            "timeout(${1:5s}) {\n    $0\n}",
        ),
        keyword_item(
            "cooldown",
            "Cooldown decorator",
            "cooldown(${1:10s}) {\n    $0\n}",
        ),
        keyword_item(
            "succeed_always",
            "Always succeed",
            "succeed_always {\n    $0\n}",
        ),
        keyword_item("fail_always", "Always fail", "fail_always {\n    $0\n}"),
    ]
}

/// Get life arc keywords
fn life_arc_keyword_completions() -> Vec<CompletionItem> {
    vec![
        keyword_item(
            "state",
            "Define a life arc state",
            "state ${1:name} {\n    $0\n}",
        ),
        keyword_item(
            "on",
            "Define a transition",
            "on ${1:condition} -> ${2:target_state}",
        ),
    ]
}

/// Get relationship keywords
fn relationship_keyword_completions() -> Vec<CompletionItem> {
    vec![
        keyword_item(
            "as",
            "Define participant role",
            "${1:CharacterName} as ${2:role} {\n    $0\n}",
        ),
        keyword_item("self", "Reference self in relationships", "self.${1:field}"),
        keyword_item("other", "Reference other participant", "other.${1:field}"),
    ]
}

fn keyword_item(label: &str, detail: &str, snippet: &str) -> CompletionItem {
    CompletionItem {
        label: label.to_string(),
        kind: Some(CompletionItemKind::KEYWORD),
        detail: Some(detail.to_string()),
        documentation: Some(Documentation::MarkupContent(MarkupContent {
            kind: MarkupKind::Markdown,
            value: format!("**{}**\n\n{}", label, detail),
        })),
        insert_text: Some(snippet.to_string()),
        insert_text_format: Some(tower_lsp::lsp_types::InsertTextFormat::SNIPPET),
        ..Default::default()
    }
}

fn simple_item(label: &str, detail: &str, snippet: &str) -> CompletionItem {
    CompletionItem {
        label: label.to_string(),
        kind: Some(CompletionItemKind::PROPERTY),
        detail: Some(detail.to_string()),
        insert_text: Some(snippet.to_string()),
        insert_text_format: Some(tower_lsp::lsp_types::InsertTextFormat::SNIPPET),
        ..Default::default()
    }
}
