require "json"
require "./drug_lut"
require "./alcohol_lut"
require "./caffeine_lut"
require "./cannabis_lut"
require "./meds_lut"
require "./vitals_tracker"
require "./data_analysis"
require "./data_files"
require "./fuzzy"

module JosieHealth
  module LUT
    VERSION = "0.1.0"

    # Main entry point for drug normalization
    def self.normalize_substance(input : String) : String?
      DrugLUT.normalize(input.strip.downcase)
    end

    # Get all known aliases for a substance
    def self.get_aliases(canonical_name : String) : Array(String)
      DrugLUT.get_aliases(canonical_name)
    end

    # Check if a substance is known
    def self.known_substance?(input : String) : Bool
      normalize_substance(input) != nil
    end

    # Get all canonical substance names
    def self.all_substances : Array(String)
      DrugLUT.all_canonical_names
    end

    # Get substance info with metadata
    def self.substance_info(input : String) : NamedTuple(canonical_name: String?, aliases: Array(String))
      canonical = normalize_substance(input)
      aliases = canonical ? get_aliases(canonical) : [] of String
      {canonical_name: canonical, aliases: aliases}
    end

    # Export all mappings as JSON for diffing/migration purposes
    # Returns a hash with alias -> canonical for both substances and routes
    def self.export_mappings : String
      {
        "version"    => VERSION,
        "substances" => DrugLUT.export_alias_map,
        "routes"     => RouteLUT.export_alias_map,
      }.to_json
    end

    # Normalize route of administration
    def self.normalize_route(input : String) : String?
      RouteLUT.normalize(input)
    end

    # Fuzzy substance normalization (exact match first, then Damerau-Levenshtein)
    def self.fuzzy_normalize_substance(input : String) : FuzzyResult?
      DrugLUT.fuzzy_normalize(input)
    end

    # Fuzzy route normalization (exact match first, then Damerau-Levenshtein)
    def self.fuzzy_normalize_route(input : String) : FuzzyResult?
      RouteLUT.fuzzy_normalize(input)
    end

    # ============================================
    # Alcohol LUT methods
    # ============================================

    # Look up an alcoholic beverage by brand name
    def self.lookup_alcohol(name : String)
      AlcoholLUT.lookup_brand(name)
    end

    # Check if a substance is an alcoholic beverage
    def self.is_alcohol?(name : String) : Bool
      AlcoholLUT.is_alcohol?(name)
    end

    # Calculate alcohol dose from dosage string and substance
    def self.calculate_alcohol_dose(dosage : String, substance : String, abv_override : Float64? = nil)
      AlcoholLUT.calculate_dose(dosage, substance, abv_override)
    end

    # Parse dosage string for alcohol (e.g., "2pints", "500ml")
    def self.parse_alcohol_dosage(dosage : String)
      AlcoholLUT.parse_dosage(dosage)
    end

    # Calculate alcohol grams from volume and ABV
    def self.calculate_alcohol_grams(volume_ml : Float64, abv_percent : Float64) : Float64
      AlcoholLUT.calculate_grams(volume_ml, abv_percent)
    end

    # ============================================
    # Caffeine LUT methods
    # ============================================

    # Look up a caffeinated product by brand name
    def self.lookup_caffeine(name : String)
      CaffeineLUT.lookup_brand(name)
    end

    # Check if a substance is a caffeinated beverage/product
    def self.is_caffeine_source?(name : String) : Bool
      CaffeineLUT.is_caffeine_source?(name)
    end

    # Calculate caffeine dose from dosage string and substance
    def self.calculate_caffeine_dose(dosage : String, substance : String)
      CaffeineLUT.calculate_dose(dosage, substance)
    end

    # Parse dosage string for caffeine (e.g., "2cans", "500ml", "2g")
    def self.parse_caffeine_dosage(dosage : String)
      CaffeineLUT.parse_dosage(dosage)
    end

    # Lookup caffeine mg per gram for powder sources (e.g., matcha)
    def self.lookup_caffeine_powder_mg_per_g(name : String) : Int32?
      CaffeineLUT.lookup_powder_mg_per_g(name)
    end

    # ============================================
    # Meds LUT methods (injectable medications)
    # ============================================

    # Look up an injectable medication by name
    def self.lookup_medication(name : String)
      MedsLUT.lookup_medication(name)
    end

    # Check if a substance is an injectable medication
    def self.is_injectable_med?(name : String) : Bool
      MedsLUT.is_injectable_med?(name)
    end

    # Calculate medication dose from ml to mg
    # Supports @concentration syntax (e.g., "een@20" for 20mg/ml)
    def self.calculate_meds_dose(substance : String, dosage : String, unit : String)
      MedsLUT.calculate_dose(substance, dosage, unit)
    end

    # Parse substance name with optional concentration override
    def self.parse_meds_concentration(name : String)
      MedsLUT.parse_substance_concentration(name)
    end

    # ============================================
    # Cannabis LUT methods
    # ============================================

    # Look up a cannabis source by name (joint, cart, bowl, etc.)
    def self.lookup_cannabis(name : String)
      CannabisLUT.lookup_source(name)
    end

    # Check if a substance is a cannabis source
    def self.is_cannabis_source?(name : String) : Bool
      CannabisLUT.is_cannabis_source?(name)
    end

    # Calculate cannabis dose from dosage string and source
    def self.calculate_cannabis_dose(dosage : String, source : String)
      CannabisLUT.calculate_dose(dosage, source)
    end

    # Parse dosage string for cannabis (e.g., "5puff", "1/3", "2hit")
    def self.parse_cannabis_dosage(dosage : String)
      CannabisLUT.parse_dosage(dosage)
    end
  end
end
