use crate::Emitter;
use crate::go::names::go_name;
use crate::go::patterns::tree_emitter::TreeEmitter;
use crate::go::utils::DiscardGuard;
use crate::go::write_line;
use syntax::ast::{Expression, MatchArm};
use syntax::types::Type;

impl Emitter<'_> {
    pub(crate) fn emit_match(
        &mut self,
        output: &mut String,
        subject: &Expression,
        arms: &[MatchArm],
        ty: &Type,
    ) {
        if subject.get_type().is_never() {
            self.emit_statement(output, subject);
            return;
        }
        let subject_var = self.emit_match_subject_var(output, subject, arms);
        let guard = if matches!(subject, Expression::Literal { .. }) {
            None
        } else {
            Some(DiscardGuard::new(output, &subject_var))
        };
        let tree_emitter = TreeEmitter::new(self, arms, ty, subject_var);
        tree_emitter.emit(output);
        if let Some(guard) = guard {
            guard.finish(output);
        }
    }

    fn emit_match_subject_var(
        &mut self,
        output: &mut String,
        subject: &Expression,
        arms: &[MatchArm],
    ) -> String {
        if let Expression::Identifier { value, .. } = subject {
            let name = value.to_string();
            let has_collision = arms
                .iter()
                .any(|arm| Emitter::pattern_binds_name(&arm.pattern, &name));
            if !has_collision && !name.contains('.') {
                return self
                    .scope
                    .bindings
                    .get(&name)
                    .map(|s| s.to_string())
                    .unwrap_or_else(|| go_name::escape_reserved(&name).into_owned());
            }
        }
        if matches!(subject, Expression::Literal { .. }) {
            return self.emit_operand(output, subject);
        }
        let var = self.fresh_var(Some("subject"));
        self.declare(&var);
        let subject_expression = self.emit_composite_value(output, subject);
        write_line!(output, "{} := {}", var, subject_expression);
        var
    }
}
