import {
  COMPLETE_HOSPITALIZATION_CONVERSION,
  CONFIRMATION_OVERRIDE,
  EMERGENCY_PASSAGE,
  HOSPITAL_RESTRICTED_RESERVE_CARE,
  IGS,
  INNOVATION_NUMBER,
  NON_PROGRAMMED,
  RAAC_CARE,
  RADIO_THERAPY_DOSIMETRY_TYPE,
  RADIO_THERAPY_MACHINE_TYPE,
  RUM_DESTINATION,
  RUM_ENTRY_MODE,
  RUM_EXIT_MODE,
  RUM_PROVENANCE,
  RUMObject,
  SEX,
  SPECIAL_PATIENT_MONITORING,
  TARIFFICATION_RESTRICTION,
  TOTAL_INTERVENTIONS_CATEGORY
} from '../../../types'
import { parseRUMObject } from './parse-rum'

describe('parseRUMObject', () => {
  describe('Valid inputs', () => {
    it('should parse a minimal valid RUM record', () => {
      const input = {
        sex: '1',
        entryMode: '0'
      }

      const result = parseRUMObject(input)

      expect(result).toEqual(input)
      expect(result.sex).toBe('1')
      expect(result.entryMode).toBe('0')
    })

    it('should parse a complete valid RUM record', () => {
      const input: RUMObject = {
        FINESS: '123456789',
        RSS: '12345678901234567890',
        ADM: '12345678',
        RUM: '87654321',
        birthDate: '01011990',
        sex: SEX.FEMALE,
        uMed: '11111111',
        authorisation: '08',
        entryDate: '15032024',
        entryMode: RUM_ENTRY_MODE.ENTRY_MODE_0,
        provenance: RUM_PROVENANCE.PROVENANCE_2,
        exitDate: '20032024',
        exitMode: RUM_EXIT_MODE.EXIT_MODE_0,
        destination: RUM_DESTINATION.DESTINATION_4,
        cpRes: '75001',
        weight: '0750',
        ageGestation: '40',
        lastMensDate: '01012024',
        session: 2,
        nDA: 5,
        nDAD: 3,
        nZA: 2,
        DP: '12345678',
        DR: '87654321',
        IGS: IGS.IGS_EMPTY,
        conf: CONFIRMATION_OVERRIDE.CONFIRMATION_OVERRIDE_1,
        rtM: RADIO_THERAPY_MACHINE_TYPE.RTM_A,
        rtD: RADIO_THERAPY_DOSIMETRY_TYPE.RTDT_B,
        innov: INNOVATION_NUMBER.INNOVATION_NUMBER_1,
        conv: COMPLETE_HOSPITALIZATION_CONVERSION.COMPLETE_HOSPITALIZATION_CONVERSION_1,
        raac: RAAC_CARE.RAAC_CARE_1,
        spec: SPECIAL_PATIENT_MONITORING.SPECIAL_PATIENT_MONITORING_1,
        RH: HOSPITAL_RESTRICTED_RESERVE_CARE.HOSPITAL_RESTRICTED_RESERVE_CARE_1,
        tarif: TARIFFICATION_RESTRICTION.TARIFFICATION_RESTRICTION_1,
        cat: TOTAL_INTERVENTIONS_CATEGORY.TOTAL_INTERVENTIONS_CATEGORY_A,
        NP: NON_PROGRAMMED.NON_PROGRAMMED_1,
        ER: EMERGENCY_PASSAGE.EMERGENCY_PASSAGE_5,
        FILL: 'test_fill',
        RES: 'test_res',
        DAs: ['12345678', '87654321'],
        DADs: ['11111111', '22222222'],
        ZAs: [
          {
            date: '15032024',
            code: '12345678',
            ext: '-01',
            phase: '1',
            act: '2',
            diag: '03',
            mod: '1234',
            RE: '1',
            AN: '2',
            qty: '01'
          }
        ]
      }

      const result = parseRUMObject(input)

      expect(result).toEqual(input)
      expect(result.FINESS).toBe('123456789')
      expect(result.sex).toBe('2')
      expect(result.ZAs).toHaveLength(1)
      expect(result.ZAs?.[0].date).toBe('15032024')
    })

    it('should parse record with empty optional fields', () => {
      const input: RUMObject = {
        FINESS: '123456789',
        sex: SEX.MALE
      }

      const result = parseRUMObject(input)

      expect(result).toEqual(input)
      expect(result.FINESS).toBe('123456789')
      expect(result.sex).toBe('1')
      expect(result.birthDate).toBeUndefined()
    })

    it('should parse record with arrays', () => {
      const input = {
        DAs: ['12345678'],
        DADs: ['87654321', '11111111'],
        ZAs: [
          {
            date: '15032024',
            code: '12345678'
          },
          {
            date: '16032024',
            code: '87654321',
            ext: '-02'
          }
        ]
      }

      const result = parseRUMObject(input)

      expect(result.DAs).toEqual(['12345678'])
      expect(result.DADs).toEqual(['87654321', '11111111'])
      expect(result.ZAs).toHaveLength(2)
      expect(result.ZAs?.[1].ext).toBe('-02')
    })
  })

  describe('Invalid inputs', () => {
    it('should throw error for invalid sex value', () => {
      const input = {
        sex: '3' // Invalid: only '1' or '2' allowed
      }

      expect(() => parseRUMObject(input)).toThrow()
    })

    it('should throw error for invalid FINESS length', () => {
      const input: RUMObject = {
        FINESS: '12345' // Invalid: should be 9 characters
      }

      expect(() => parseRUMObject(input)).toThrow()
    })

    it('should throw error for invalid date format', () => {
      const input = {
        birthDate: '1990-01-01' // Invalid: should be 8 characters DDMMYYYY
      }

      expect(() => parseRUMObject(input)).toThrow()
    })

    it('should throw error for invalid entryMode', () => {
      const input = {
        entryMode: '9' // Invalid: only '0'-'8' allowed
      }

      expect(() => parseRUMObject(input)).toThrow()
    })

    it('should throw error for invalid weight format', () => {
      const input = {
        weight: '75' // Invalid: should be 4 characters
      }

      expect(() => parseRUMObject(input)).toThrow()
    })

    it('should throw error for invalid ZA section', () => {
      const input = {
        ZAs: [
          {
            date: '150324', // Invalid: should be 8 characters
            code: '12345678'
          }
        ]
      }

      expect(() => parseRUMObject(input)).toThrow()
    })

    it('should throw error for invalid DA array elements', () => {
      const input = {
        DAs: ['1234'] // Invalid: each element should be 8 characters
      }

      expect(() => parseRUMObject(input)).toThrow()
    })
  })

  describe('Edge cases', () => {
    it('should handle empty object', () => {
      const input = {}

      const result = parseRUMObject(input)

      expect(result).toEqual({})
    })

    it('should handle null/undefined values gracefully', () => {
      const input = {
        sex: '1',
        FINESS: undefined,
        RSS: null
      }

      // Zod doesn't accept null values for optional fields, only undefined
      expect(() => parseRUMObject(input)).toThrow()
    })

    it('should handle undefined values gracefully', () => {
      const input = {
        sex: '1',
        FINESS: undefined
      }

      // undefined should be fine for optional fields
      expect(() => parseRUMObject(input)).not.toThrow()
    })

    it('should validate enum values strictly', () => {
      const validInput = {
        IGS: '1',
        rtM: 'F',
        rtD: '9'
      }

      expect(() => parseRUMObject(validInput)).not.toThrow()

      const invalidInput = {
        rtM: 'G' // Invalid enum value
      }

      expect(() => parseRUMObject(invalidInput)).toThrow()
    })

    it('should handle complex ZA sections with all optional fields', () => {
      const input = {
        ZAs: [
          {
            date: '15032024',
            code: '12345678',
            ext: '-01',
            phase: '2',
            act: '3',
            diag: '04',
            mod: '5678',
            RE: '1',
            AN: '0',
            qty: '99'
          }
        ]
      }

      const result = parseRUMObject(input)

      expect(result.ZAs?.[0]).toEqual(input.ZAs[0])
    })

    it('should validate that conf only accepts "1" or "2"', () => {
      const validInput = { conf: '1' }
      expect(() => parseRUMObject(validInput)).not.toThrow()

      const validInput2 = { conf: '2' }
      expect(() => parseRUMObject(validInput2)).not.toThrow()

      const invalidInput = { conf: '3' }
      expect(() => parseRUMObject(invalidInput)).toThrow()
    })

    it('should validate NP only accepts 1 or 2', () => {
      const validInput: RUMObject = { NP: NON_PROGRAMMED.NON_PROGRAMMED_1 }
      expect(() => parseRUMObject(validInput)).not.toThrow()

      const invalidInput = { NP: '3' }
      expect(() => parseRUMObject(invalidInput)).toThrow()
    })
  })

  describe('Type validation', () => {
    it('should return correct TypeScript type', () => {
      const input = {
        sex: '1' as const,
        nDA: 5
      }

      const result: RUMObject = parseRUMObject(input)

      expect(typeof result.sex).toBe('string')
      expect(typeof result.nDA).toBe('number')
    })

    it('should handle numeric fields correctly', () => {
      const input = {
        nDA: 10,
        nDAD: 5,
        nZA: 2
      }

      const result = parseRUMObject(input)

      expect(result.nDA).toBe(10)
      expect(result.nDAD).toBe(5)
      expect(result.nZA).toBe(2)
      expect(typeof result.nDA).toBe('number')
    })
  })
})
