use serde::{Deserialize, Serialize};

use crate::errors::LabGeneticsError;

/// A genetic variant — parsed from VCF, JSON, or free text
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Variant {
    /// rsID (e.g., "rs1801133") or custom ID
    pub id: String,
    /// Gene symbol (e.g., "MTHFR")
    #[serde(default)]
    pub gene: String,
    /// Chromosome
    #[serde(default)]
    pub chrom: String,
    /// Position
    #[serde(default)]
    pub pos: u64,
    /// Reference allele
    #[serde(default)]
    pub ref_allele: String,
    /// Alternate allele
    #[serde(default)]
    pub alt_allele: String,
    /// Genotype (e.g., "0/1", "1/1", "C/T", "e3/e4")
    #[serde(default)]
    pub genotype: String,
    /// Zygosity: homozygous, heterozygous, hemizygous
    #[serde(default)]
    pub zygosity: String,
    /// Common name (e.g., "C677T", "e4/e4")
    #[serde(default)]
    pub common_name: String,
}

impl Variant {
    /// Create a variant from a free-text identifier
    pub fn from_id(id: &str) -> Self {
        let trimmed = id.trim();

        // Try to parse "GENE VARIANT" format: "MTHFR C677T"
        let (gene, common_name) = if let Some(pos) = trimmed.find(|c: char| c.is_whitespace()) {
            let (g, v) = trimmed.split_at(pos);
            (g.trim().to_uppercase(), v.trim().to_string())
        } else {
            // Single token: could be rsID or gene name
            if trimmed.starts_with("rs") {
                (String::new(), String::new())
            } else {
                (trimmed.to_uppercase(), String::new())
            }
        };

        // Detect genotype from common name patterns
        let genotype = if common_name.contains('/') {
            common_name.clone()
        } else {
            String::new()
        };

        Variant {
            id: if trimmed.starts_with("rs") {
                trimmed.to_lowercase()
            } else {
                trimmed.to_string()
            },
            gene,
            chrom: String::new(),
            pos: 0,
            ref_allele: String::new(),
            alt_allele: String::new(),
            genotype,
            zygosity: String::new(),
            common_name,
        }
    }
}

/// Parse a VCF file into variants
pub fn parse_vcf(input: &str) -> Result<Vec<Variant>, LabGeneticsError> {
    let mut variants = Vec::new();

    for line in input.lines() {
        // Skip headers
        if line.starts_with('#') {
            continue;
        }

        let fields: Vec<&str> = line.split('\t').collect();
        if fields.len() < 5 {
            continue;
        }

        let chrom = fields[0].to_string();
        let pos: u64 = fields[1]
            .parse()
            .map_err(|_| LabGeneticsError::ParseError(format!("Invalid position: {}", fields[1])))?;
        let id = if fields[2] == "." {
            format!("{}:{}", chrom, pos)
        } else {
            fields[2].to_string()
        };
        let ref_allele = fields[3].to_string();
        let alt_allele = fields[4].to_string();

        // Extract genotype from sample column if present
        let genotype = if fields.len() >= 10 {
            let format_fields: Vec<&str> = fields[8].split(':').collect();
            let sample_fields: Vec<&str> = fields[9].split(':').collect();
            let gt_idx = format_fields.iter().position(|&f| f == "GT");
            gt_idx
                .and_then(|i| sample_fields.get(i))
                .map(|s| s.to_string())
                .unwrap_or_default()
        } else {
            String::new()
        };

        let zygosity = match genotype.as_str() {
            "0/1" | "0|1" | "1|0" => "heterozygous".to_string(),
            "1/1" | "1|1" => "homozygous".to_string(),
            "0/0" | "0|0" => "wild_type".to_string(),
            _ => String::new(),
        };

        variants.push(Variant {
            id,
            gene: String::new(), // Filled in during catalog lookup
            chrom,
            pos,
            ref_allele,
            alt_allele,
            genotype,
            zygosity,
            common_name: String::new(),
        });
    }

    if variants.is_empty() {
        return Err(LabGeneticsError::ParseError(
            "No variants found in VCF".into(),
        ));
    }

    Ok(variants)
}
