use crate::de::enum_adjacently;
use crate::de::enum_externally;
use crate::de::enum_internally;
use crate::de::enum_untagged;
use crate::de::identifier;
use crate::de::{field_i, FieldWithAliases, Parameters};
use crate::fragment::{Expr, Fragment, Stmts};
use crate::internals::ast::Variant;
use crate::internals::attr;
use crate::private;
use proc_macro2::TokenStream;
use quote::quote;

/// Generates `Deserialize::deserialize` body for an `enum Enum {...}`
pub(super) fn deserialize(
    params: &Parameters,
    variants: &[Variant],
    cattrs: &attr::Container,
) -> Fragment {
    // The variants have already been checked (in ast.rs) that all untagged variants appear at the end
    match variants.iter().position(|var| var.attrs.untagged()) {
        Some(variant_idx) => {
            let (tagged, untagged) = variants.split_at(variant_idx);
            let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs));
            // Ignore any error associated with non-untagged deserialization so that we
            // can fall through to the untagged variants. This may be infallible so we
            // need to provide the error type.
            let first_attempt = quote! {
                if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() {
                    return _serde::#private::Ok(__ok);
                }
            };
            enum_untagged::deserialize(params, untagged, cattrs, Some(first_attempt))
        }
        None => deserialize_homogeneous_enum(params, variants, cattrs),
    }
}

fn deserialize_homogeneous_enum(
    params: &Parameters,
    variants: &[Variant],
    cattrs: &attr::Container,
) -> Fragment {
    match cattrs.tag() {
        attr::TagType::External => enum_externally::deserialize(params, variants, cattrs),
        attr::TagType::Internal { tag } => {
            enum_internally::deserialize(params, variants, cattrs, tag)
        }
        attr::TagType::Adjacent { tag, content } => {
            enum_adjacently::deserialize(params, variants, cattrs, tag, content)
