require "time"

module JosieHealth::LUT
  # Vital signs ranges based on medical standards
  VITAL_RANGES = {
    "pulse" => {
      "normal_min"      => 60,
      "normal_max"      => 100,
      "concerning_low"  => 50,
      "concerning_high" => 120,
      "critical_low"    => 40,
      "critical_high"   => 150,
    },
    "systolic_bp" => {
      "normal_min"      => 90,
      "normal_max"      => 120,
      "concerning_low"  => 80,
      "concerning_high" => 140,
      "critical_low"    => 70,
      "critical_high"   => 180,
    },
    "diastolic_bp" => {
      "normal_min"      => 60,
      "normal_max"      => 80,
      "concerning_low"  => 50,
      "concerning_high" => 90,
      "critical_low"    => 40,
      "critical_high"   => 120,
    },
    "blood_oxygen" => {
      "normal_min"      => 95,
      "normal_max"      => 100,
      "concerning_low"  => 90,
      "concerning_high" => 100,
      "critical_low"    => 85,
      "critical_high"   => 100,
    },
  }

  record VitalReading,
    timestamp : Time,
    user_id : String,
    pulse : Int32?,
    systolic_bp : Int32?,
    diastolic_bp : Int32?,
    blood_oxygen : Int32?,
    notes : String?,
    time_from_dose : Time::Span? = nil

  record VitalValidationResult,
    valid : Bool,
    errors : Array(String)

  record VitalLogResult,
    success : Bool,
    message : String,
    concerning_alerts : Array(String) = [] of String

  record VitalQueryResult,
    found : Bool,
    vitals : Array(VitalReading),
    error : String? = nil

  module VitalsTracker
    extend self

    def validate_vitals(pulse : Int32? = nil, systolic_bp : Int32? = nil,
                        diastolic_bp : Int32? = nil, blood_oxygen : Int32? = nil) : VitalValidationResult
      errors = [] of String

      if pulse && (pulse < 20 || pulse > 300)
        errors << "pulse must be between 20-300 bpm"
      end

      if systolic_bp && (systolic_bp < 50 || systolic_bp > 300)
        errors << "systolic BP must be between 50-300 mmHg"
      end

      if diastolic_bp && (diastolic_bp < 30 || diastolic_bp > 200)
        errors << "diastolic BP must be between 30-200 mmHg"
      end

      if blood_oxygen && (blood_oxygen < 70 || blood_oxygen > 100)
        errors << "blood oxygen must be between 70-100%"
      end

      # Check BP relationship if both provided
      if systolic_bp && diastolic_bp && systolic_bp <= diastolic_bp
        errors << "systolic BP must be higher than diastolic BP"
      end

      VitalValidationResult.new(
        valid: errors.empty?,
        errors: errors
      )
    end

    def check_concerning_vitals(pulse : Int32? = nil, systolic_bp : Int32? = nil,
                                diastolic_bp : Int32? = nil, blood_oxygen : Int32? = nil) : Array(String)
      alerts = [] of String

      if pulse
        ranges = VITAL_RANGES["pulse"]
        if pulse <= ranges["critical_low"]
          alerts << "CRITICAL: Pulse extremely low (#{pulse} bpm)"
        elsif pulse >= ranges["critical_high"]
          alerts << "CRITICAL: Pulse extremely high (#{pulse} bpm)"
        elsif pulse <= ranges["concerning_low"]
          alerts << "CONCERNING: Pulse low (#{pulse} bpm)"
        elsif pulse >= ranges["concerning_high"]
          alerts << "CONCERNING: Pulse elevated (#{pulse} bpm)"
        end
      end

      if systolic_bp
        ranges = VITAL_RANGES["systolic_bp"]
        if systolic_bp <= ranges["critical_low"]
          alerts << "CRITICAL: Systolic BP extremely low (#{systolic_bp} mmHg)"
        elsif systolic_bp >= ranges["critical_high"]
          alerts << "CRITICAL: Systolic BP extremely high (#{systolic_bp} mmHg)"
        elsif systolic_bp <= ranges["concerning_low"]
          alerts << "CONCERNING: Systolic BP low (#{systolic_bp} mmHg)"
        elsif systolic_bp >= ranges["concerning_high"]
          alerts << "CONCERNING: Systolic BP elevated (#{systolic_bp} mmHg)"
        end
      end

      if diastolic_bp
        ranges = VITAL_RANGES["diastolic_bp"]
        if diastolic_bp <= ranges["critical_low"]
          alerts << "CRITICAL: Diastolic BP extremely low (#{diastolic_bp} mmHg)"
        elsif diastolic_bp >= ranges["critical_high"]
          alerts << "CRITICAL: Diastolic BP extremely high (#{diastolic_bp} mmHg)"
        elsif diastolic_bp <= ranges["concerning_low"]
          alerts << "CONCERNING: Diastolic BP low (#{diastolic_bp} mmHg)"
        elsif diastolic_bp >= ranges["concerning_high"]
          alerts << "CONCERNING: Diastolic BP elevated (#{diastolic_bp} mmHg)"
        end
      end

      if blood_oxygen
        ranges = VITAL_RANGES["blood_oxygen"]
        if blood_oxygen <= ranges["critical_low"]
          alerts << "CRITICAL: Blood oxygen critically low (#{blood_oxygen}%)"
        elsif blood_oxygen <= ranges["concerning_low"]
          alerts << "CONCERNING: Blood oxygen low (#{blood_oxygen}%)"
        end
      end

      alerts
    end

    def build_vitals_summary(pulse : Int32? = nil, systolic_bp : Int32? = nil,
                             diastolic_bp : Int32? = nil, blood_oxygen : Int32? = nil) : String
      parts = [] of String

      parts << "#{pulse} bpm" if pulse

      if systolic_bp && diastolic_bp
        parts << "#{systolic_bp}/#{diastolic_bp} mmHg"
      elsif systolic_bp
        parts << "#{systolic_bp}/- mmHg"
      elsif diastolic_bp
        parts << "-/#{diastolic_bp} mmHg"
      end

      parts << "#{blood_oxygen}% O2" if blood_oxygen

      parts.join(", ")
    end

    def create_vital_reading(user_id : String, pulse : Int32? = nil, systolic_bp : Int32? = nil,
                             diastolic_bp : Int32? = nil, blood_oxygen : Int32? = nil,
                             notes : String? = nil, timestamp : Time = Time.utc) : VitalReading?
      # Validate at least one vital is provided
      vitals_provided = [pulse, systolic_bp, diastolic_bp, blood_oxygen].compact
      return nil if vitals_provided.empty?

      # Validate ranges
      validation = validate_vitals(pulse, systolic_bp, diastolic_bp, blood_oxygen)
      return nil unless validation.valid

      VitalReading.new(
        timestamp: timestamp,
        user_id: user_id.downcase,
        pulse: pulse,
        systolic_bp: systolic_bp,
        diastolic_bp: diastolic_bp,
        blood_oxygen: blood_oxygen,
        notes: notes
      )
    end

    def vitals_within_window(vitals : Array(VitalReading), dose_timestamp : Time,
                             window_hours : Int32 = 2) : Array(VitalReading)
      window_seconds = window_hours * 3600

      vitals.select do |vital|
        time_diff = (vital.timestamp - dose_timestamp).abs.total_seconds
        time_diff <= window_seconds
      end.map do |vital|
        # Add time_from_dose for correlation analysis
        VitalReading.new(
          timestamp: vital.timestamp,
          user_id: vital.user_id,
          pulse: vital.pulse,
          systolic_bp: vital.systolic_bp,
          diastolic_bp: vital.diastolic_bp,
          blood_oxygen: vital.blood_oxygen,
          notes: vital.notes,
          time_from_dose: vital.timestamp - dose_timestamp
        )
      end.sort_by(&.timestamp)
    end
  end
end
