import Contacts

struct ContactLabelMapper {
  static func toRecordLabel(_ cnLabel: String?) -> String {
    guard let cnLabel = nonBlankLabel(cnLabel) else {
      return otherRecordLabel
    }
    // Tradeoff: If a system label (e.g. CNFutureLabel) is missing from cnLabelToRecordLabel,
    // we expose its prefix and suffix to JS so writing it back preserves the native label.
    // Read: toRecordLabel(CNFutureLabel) -> "_$!<FutureLabel>!$_"
    // Write: toCNLabel("_$!<FutureLabel>!$_") -> the same string value as CNFutureLabel.
    // Exposing "futureLabel" instead would replace the native label with a custom label on write.
    return cnLabelToRecordLabel[cnLabel] ?? cnLabel
  }

  static func toCNLabel(_ recordLabel: String?) -> String {
    guard let recordLabel = nonBlankLabel(recordLabel) else {
      return CNLabelOther
    }
    let lowercasedRecordLabel = recordLabel.lowercased()
    return lowercasedRecordLabelToCNLabel[lowercasedRecordLabel] ?? recordLabel
  }

  private static let otherRecordLabel = "other"

  private static let lowercasedRecordLabelToCNLabel = Dictionary(
    uniqueKeysWithValues: cnLabelToRecordLabel.map { cnLabel, recordLabel in
      let lowercasedRecordLabel = recordLabel.lowercased()
      return (lowercasedRecordLabel, cnLabel)
    }
  )

  private static func nonBlankLabel(_ label: String?) -> String? {
    guard let label, label.contains(where: { !$0.isWhitespace }) else {
      return nil
    }
    return label
  }

  // This map contains every CNLabel defined in Contact framework.
  // TODO(@Wenszel): should be checked on every iOS release
  private static let cnLabelToRecordLabel: [String: String] = [
    CNLabelDateAnniversary: "anniversary",
    CNLabelEmailiCloud: "iCloud",
    CNLabelHome: "home",
    CNLabelOther: otherRecordLabel,
    CNLabelSchool: "school",
    CNLabelURLAddressHomePage: "homepage",
    CNLabelWork: "work",
    CNLabelPhoneNumberAppleWatch: "appleWatch",
    CNLabelPhoneNumberHomeFax: "faxHome",
    CNLabelPhoneNumberiPhone: "iPhone",
    CNLabelPhoneNumberMain: "main",
    CNLabelPhoneNumberMobile: "mobile",
    CNLabelPhoneNumberOtherFax: "otherFax",
    CNLabelPhoneNumberPager: "pager",
    CNLabelPhoneNumberWorkFax: "faxWork",
    CNLabelContactRelationAssistant: "assistant",
    CNLabelContactRelationAunt: "aunt",
    CNLabelContactRelationAuntFathersBrothersWife: "auntFathersBrothersWife",
    CNLabelContactRelationAuntFathersElderBrothersWife: "auntFathersElderBrothersWife",
    CNLabelContactRelationAuntFathersElderSister: "auntFathersElderSister",
    CNLabelContactRelationAuntFathersSister: "auntFathersSister",
    CNLabelContactRelationAuntFathersYoungerBrothersWife: "auntFathersYoungerBrothersWife",
    CNLabelContactRelationAuntFathersYoungerSister: "auntFathersYoungerSister",
    CNLabelContactRelationAuntMothersBrothersWife: "auntMothersBrothersWife",
    CNLabelContactRelationAuntMothersElderSister: "auntMothersElderSister",
    CNLabelContactRelationAuntMothersSister: "auntMothersSister",
    CNLabelContactRelationAuntMothersYoungerSister: "auntMothersYoungerSister",
    CNLabelContactRelationAuntParentsElderSister: "auntParentsElderSister",
    CNLabelContactRelationAuntParentsSister: "auntParentsSister",
    CNLabelContactRelationAuntParentsYoungerSister: "auntParentsYoungerSister",
    CNLabelContactRelationBoyfriend: "boyfriend",
    CNLabelContactRelationBrother: "brother",
    CNLabelContactRelationBrotherInLaw: "brotherInLaw",
    CNLabelContactRelationBrotherInLawElderSistersHusband: "brotherInLawElderSistersHusband",
    CNLabelContactRelationBrotherInLawHusbandsBrother: "brotherInLawHusbandsBrother",
    CNLabelContactRelationBrotherInLawHusbandsSistersHusband: "brotherInLawHusbandsSistersHusband",
    CNLabelContactRelationBrotherInLawSistersHusband: "brotherInLawSistersHusband",
    CNLabelContactRelationBrotherInLawSpousesBrother: "brotherInLawSpousesBrother",
    CNLabelContactRelationBrotherInLawWifesBrother: "brotherInLawWifesBrother",
    CNLabelContactRelationBrotherInLawWifesSistersHusband: "brotherInLawWifesSistersHusband",
    CNLabelContactRelationBrotherInLawYoungerSistersHusband: "brotherInLawYoungerSistersHusband",
    CNLabelContactRelationChild: "child",
    CNLabelContactRelationChildInLaw: "childInLaw",
    CNLabelContactRelationCoBrotherInLaw: "coBrotherInLaw",
    CNLabelContactRelationCoFatherInLaw: "coFatherInLaw",
    CNLabelContactRelationColleague: "colleague",
    CNLabelContactRelationCoMotherInLaw: "coMotherInLaw",
    CNLabelContactRelationCoParentInLaw: "coParentInLaw",
    CNLabelContactRelationCoSiblingInLaw: "coSiblingInLaw",
    CNLabelContactRelationCoSisterInLaw: "coSisterInLaw",
    CNLabelContactRelationCousin: "cousin",
    CNLabelContactRelationCousinFathersBrothersDaughter: "cousinFathersBrothersDaughter",
    CNLabelContactRelationCousinFathersBrothersSon: "cousinFathersBrothersSon",
    CNLabelContactRelationCousinFathersSistersDaughter: "cousinFathersSistersDaughter",
    CNLabelContactRelationCousinFathersSistersSon: "cousinFathersSistersSon",
    CNLabelContactRelationCousinGrandparentsSiblingsChild: "cousinGrandparentsSiblingsChild",
    CNLabelContactRelationCousinGrandparentsSiblingsDaughter: "cousinGrandparentsSiblingsDaughter",
    CNLabelContactRelationCousinGrandparentsSiblingsSon: "cousinGrandparentsSiblingsSon",
    CNLabelContactRelationCousinMothersBrothersDaughter: "cousinMothersBrothersDaughter",
    CNLabelContactRelationCousinMothersBrothersSon: "cousinMothersBrothersSon",
    CNLabelContactRelationCousinMothersSistersDaughter: "cousinMothersSistersDaughter",
    CNLabelContactRelationCousinMothersSistersSon: "cousinMothersSistersSon",
    CNLabelContactRelationCousinOrSiblingsChild: "cousinOrSiblingsChild",
    CNLabelContactRelationCousinParentsSiblingsChild: "cousinParentsSiblingsChild",
    CNLabelContactRelationCousinParentsSiblingsDaughter: "cousinParentsSiblingsDaughter",
    CNLabelContactRelationCousinParentsSiblingsSon: "cousinParentsSiblingsSon",
    CNLabelContactRelationDaughter: "daughter",
    CNLabelContactRelationDaughterInLaw: "daughterInLaw",
    CNLabelContactRelationDaughterInLawOrSisterInLaw: "daughterInLawOrSisterInLaw",
    CNLabelContactRelationDaughterInLawOrStepdaughter: "daughterInLawOrStepdaughter",
    CNLabelContactRelationElderBrother: "elderBrother",
    CNLabelContactRelationElderBrotherInLaw: "elderBrotherInLaw",
    CNLabelContactRelationElderCousin: "elderCousin",
    CNLabelContactRelationElderCousinFathersBrothersDaughter: "elderCousinFathersBrothersDaughter",
    CNLabelContactRelationElderCousinFathersBrothersSon: "elderCousinFathersBrothersSon",
    CNLabelContactRelationElderCousinFathersSistersDaughter: "elderCousinFathersSistersDaughter",
    CNLabelContactRelationElderCousinFathersSistersSon: "elderCousinFathersSistersSon",
    CNLabelContactRelationElderCousinMothersBrothersDaughter: "elderCousinMothersBrothersDaughter",
    CNLabelContactRelationElderCousinMothersBrothersSon: "elderCousinMothersBrothersSon",
    CNLabelContactRelationElderCousinMothersSiblingsDaughterOrFathersSistersDaughter: "elderCousinMothersSiblingsDaughterOrFathersSistersDaughter",
    CNLabelContactRelationElderCousinMothersSiblingsSonOrFathersSistersSon: "elderCousinMothersSiblingsSonOrFathersSistersSon",
    CNLabelContactRelationElderCousinMothersSistersDaughter: "elderCousinMothersSistersDaughter",
    CNLabelContactRelationElderCousinMothersSistersSon: "elderCousinMothersSistersSon",
    CNLabelContactRelationElderCousinParentsSiblingsDaughter: "elderCousinParentsSiblingsDaughter",
    CNLabelContactRelationElderCousinParentsSiblingsSon: "elderCousinParentsSiblingsSon",
    CNLabelContactRelationElderSibling: "elderSibling",
    CNLabelContactRelationElderSiblingInLaw: "elderSiblingInLaw",
    CNLabelContactRelationElderSister: "elderSister",
    CNLabelContactRelationElderSisterInLaw: "elderSisterInLaw",
    CNLabelContactRelationEldestBrother: "eldestBrother",
    CNLabelContactRelationEldestSister: "eldestSister",
    CNLabelContactRelationFather: "father",
    CNLabelContactRelationFatherInLaw: "fatherInLaw",
    CNLabelContactRelationFatherInLawHusbandsFather: "fatherInLawHusbandsFather",
    CNLabelContactRelationFatherInLawOrStepfather: "fatherInLawOrStepfather",
    CNLabelContactRelationFatherInLawWifesFather: "fatherInLawWifesFather",
    CNLabelContactRelationFemaleCousin: "femaleCousin",
    CNLabelContactRelationFemaleFriend: "femaleFriend",
    CNLabelContactRelationFemalePartner: "femalePartner",
    CNLabelContactRelationFriend: "friend",
    CNLabelContactRelationGirlfriend: "girlfriend",
    CNLabelContactRelationGirlfriendOrBoyfriend: "girlfriendOrBoyfriend",
    CNLabelContactRelationGrandaunt: "grandaunt",
    CNLabelContactRelationGrandchild: "grandchild",
    CNLabelContactRelationGrandchildOrSiblingsChild: "grandchildOrSiblingsChild",
    CNLabelContactRelationGranddaughter: "granddaughter",
    CNLabelContactRelationGranddaughterDaughtersDaughter: "granddaughterDaughtersDaughter",
    CNLabelContactRelationGranddaughterOrNiece: "granddaughterOrNiece",
    CNLabelContactRelationGranddaughterSonsDaughter: "granddaughterSonsDaughter",
    CNLabelContactRelationGrandfather: "grandfather",
    CNLabelContactRelationGrandfatherFathersFather: "grandfatherFathersFather",
    CNLabelContactRelationGrandfatherMothersFather: "grandfatherMothersFather",
    CNLabelContactRelationGrandmother: "grandmother",
    CNLabelContactRelationGrandmotherFathersMother: "grandmotherFathersMother",
    CNLabelContactRelationGrandmotherMothersMother: "grandmotherMothersMother",
    CNLabelContactRelationGrandnephew: "grandnephew",
    CNLabelContactRelationGrandnephewBrothersGrandson: "grandnephewBrothersGrandson",
    CNLabelContactRelationGrandnephewSistersGrandson: "grandnephewSistersGrandson",
    CNLabelContactRelationGrandniece: "grandniece",
    CNLabelContactRelationGrandnieceBrothersGranddaughter: "grandnieceBrothersGranddaughter",
    CNLabelContactRelationGrandnieceSistersGranddaughter: "grandnieceSistersGranddaughter",
    CNLabelContactRelationGrandparent: "grandparent",
    CNLabelContactRelationGrandson: "grandson",
    CNLabelContactRelationGrandsonDaughtersSon: "grandsonDaughtersSon",
    CNLabelContactRelationGrandsonOrNephew: "grandsonOrNephew",
    CNLabelContactRelationGrandsonSonsSon: "grandsonSonsSon",
    CNLabelContactRelationGranduncle: "granduncle",
    CNLabelContactRelationGreatGrandchild: "greatGrandchild",
    CNLabelContactRelationGreatGrandchildOrSiblingsGrandchild: "greatGrandchildOrSiblingsGrandchild",
    CNLabelContactRelationGreatGranddaughter: "greatGranddaughter",
    CNLabelContactRelationGreatGrandfather: "greatGrandfather",
    CNLabelContactRelationGreatGrandmother: "greatGrandmother",
    CNLabelContactRelationGreatGrandparent: "greatGrandparent",
    CNLabelContactRelationGreatGrandson: "greatGrandson",
    CNLabelContactRelationHusband: "husband",
    CNLabelContactRelationMaleCousin: "maleCousin",
    CNLabelContactRelationMaleFriend: "maleFriend",
    CNLabelContactRelationMalePartner: "malePartner",
    CNLabelContactRelationManager: "manager",
    CNLabelContactRelationMother: "mother",
    CNLabelContactRelationMotherInLaw: "motherInLaw",
    CNLabelContactRelationMotherInLawHusbandsMother: "motherInLawHusbandsMother",
    CNLabelContactRelationMotherInLawOrStepmother: "motherInLawOrStepmother",
    CNLabelContactRelationMotherInLawWifesMother: "motherInLawWifesMother",
    CNLabelContactRelationNephew: "nephew",
    CNLabelContactRelationNephewBrothersSon: "nephewBrothersSon",
    CNLabelContactRelationNephewBrothersSonOrHusbandsSiblingsSon: "nephewBrothersSonOrHusbandsSiblingsSon",
    CNLabelContactRelationNephewOrCousin: "nephewOrCousin",
    CNLabelContactRelationNephewSistersSon: "nephewSistersSon",
    CNLabelContactRelationNephewSistersSonOrWifesSiblingsSon: "nephewSistersSonOrWifesSiblingsSon",
    CNLabelContactRelationNiece: "niece",
    CNLabelContactRelationNieceBrothersDaughter: "nieceBrothersDaughter",
    CNLabelContactRelationNieceBrothersDaughterOrHusbandsSiblingsDaughter: "nieceBrothersDaughterOrHusbandsSiblingsDaughter",
    CNLabelContactRelationNieceOrCousin: "nieceOrCousin",
    CNLabelContactRelationNieceSistersDaughter: "nieceSistersDaughter",
    CNLabelContactRelationNieceSistersDaughterOrWifesSiblingsDaughter: "nieceSistersDaughterOrWifesSiblingsDaughter",
    CNLabelContactRelationParent: "parent",
    CNLabelContactRelationParentInLaw: "parentInLaw",
    CNLabelContactRelationParentsElderSibling: "parentsElderSibling",
    CNLabelContactRelationParentsSibling: "parentsSibling",
    CNLabelContactRelationParentsSiblingFathersElderSibling: "parentsSiblingFathersElderSibling",
    CNLabelContactRelationParentsSiblingFathersSibling: "parentsSiblingFathersSibling",
    CNLabelContactRelationParentsSiblingFathersYoungerSibling: "parentsSiblingFathersYoungerSibling",
    CNLabelContactRelationParentsSiblingMothersElderSibling: "parentsSiblingMothersElderSibling",
    CNLabelContactRelationParentsSiblingMothersSibling: "parentsSiblingMothersSibling",
    CNLabelContactRelationParentsSiblingMothersYoungerSibling: "parentsSiblingMothersYoungerSibling",
    CNLabelContactRelationParentsYoungerSibling: "parentsYoungerSibling",
    CNLabelContactRelationPartner: "partner",
    CNLabelContactRelationSibling: "sibling",
    CNLabelContactRelationSiblingInLaw: "siblingInLaw",
    CNLabelContactRelationSiblingsChild: "siblingsChild",
    CNLabelContactRelationSister: "sister",
    CNLabelContactRelationSisterInLaw: "sisterInLaw",
    CNLabelContactRelationSisterInLawBrothersWife: "sisterInLawBrothersWife",
    CNLabelContactRelationSisterInLawElderBrothersWife: "sisterInLawElderBrothersWife",
    CNLabelContactRelationSisterInLawHusbandsBrothersWife: "sisterInLawHusbandsBrothersWife",
    CNLabelContactRelationSisterInLawHusbandsSister: "sisterInLawHusbandsSister",
    CNLabelContactRelationSisterInLawSpousesSister: "sisterInLawSpousesSister",
    CNLabelContactRelationSisterInLawWifesBrothersWife: "sisterInLawWifesBrothersWife",
    CNLabelContactRelationSisterInLawWifesSister: "sisterInLawWifesSister",
    CNLabelContactRelationSisterInLawYoungerBrothersWife: "sisterInLawYoungerBrothersWife",
    CNLabelContactRelationSon: "son",
    CNLabelContactRelationSonInLaw: "sonInLaw",
    CNLabelContactRelationSonInLawOrBrotherInLaw: "sonInLawOrBrotherInLaw",
    CNLabelContactRelationSonInLawOrStepson: "sonInLawOrStepson",
    CNLabelContactRelationSpouse: "spouse",
    CNLabelContactRelationStepbrother: "stepbrother",
    CNLabelContactRelationStepchild: "stepchild",
    CNLabelContactRelationStepdaughter: "stepdaughter",
    CNLabelContactRelationStepfather: "stepfather",
    CNLabelContactRelationStepmother: "stepmother",
    CNLabelContactRelationStepparent: "stepparent",
    CNLabelContactRelationStepsister: "stepsister",
    CNLabelContactRelationStepson: "stepson",
    CNLabelContactRelationTeacher: "teacher",
    CNLabelContactRelationUncle: "uncle",
    CNLabelContactRelationUncleFathersBrother: "uncleFathersBrother",
    CNLabelContactRelationUncleFathersElderBrother: "uncleFathersElderBrother",
    CNLabelContactRelationUncleFathersElderSistersHusband: "uncleFathersElderSistersHusband",
    CNLabelContactRelationUncleFathersSistersHusband: "uncleFathersSistersHusband",
    CNLabelContactRelationUncleFathersYoungerBrother: "uncleFathersYoungerBrother",
    CNLabelContactRelationUncleFathersYoungerSistersHusband: "uncleFathersYoungerSistersHusband",
    CNLabelContactRelationUncleMothersBrother: "uncleMothersBrother",
    CNLabelContactRelationUncleMothersElderBrother: "uncleMothersElderBrother",
    CNLabelContactRelationUncleMothersSistersHusband: "uncleMothersSistersHusband",
    CNLabelContactRelationUncleMothersYoungerBrother: "uncleMothersYoungerBrother",
    CNLabelContactRelationUncleParentsBrother: "uncleParentsBrother",
    CNLabelContactRelationUncleParentsElderBrother: "uncleParentsElderBrother",
    CNLabelContactRelationUncleParentsYoungerBrother: "uncleParentsYoungerBrother",
    CNLabelContactRelationWife: "wife",
    CNLabelContactRelationYoungerBrother: "youngerBrother",
    CNLabelContactRelationYoungerBrotherInLaw: "youngerBrotherInLaw",
    CNLabelContactRelationYoungerCousin: "youngerCousin",
    CNLabelContactRelationYoungerCousinFathersBrothersDaughter: "youngerCousinFathersBrothersDaughter",
    CNLabelContactRelationYoungerCousinFathersBrothersSon: "youngerCousinFathersBrothersSon",
    CNLabelContactRelationYoungerCousinFathersSistersDaughter: "youngerCousinFathersSistersDaughter",
    CNLabelContactRelationYoungerCousinFathersSistersSon: "youngerCousinFathersSistersSon",
    CNLabelContactRelationYoungerCousinMothersBrothersDaughter: "youngerCousinMothersBrothersDaughter",
    CNLabelContactRelationYoungerCousinMothersBrothersSon: "youngerCousinMothersBrothersSon",
    CNLabelContactRelationYoungerCousinMothersSiblingsDaughterOrFathersSistersDaughter: "youngerCousinMothersSiblingsDaughterOrFathersSistersDaughter",
    CNLabelContactRelationYoungerCousinMothersSiblingsSonOrFathersSistersSon: "youngerCousinMothersSiblingsSonOrFathersSistersSon",
    CNLabelContactRelationYoungerCousinMothersSistersDaughter: "youngerCousinMothersSistersDaughter",
    CNLabelContactRelationYoungerCousinMothersSistersSon: "youngerCousinMothersSistersSon",
    CNLabelContactRelationYoungerCousinParentsSiblingsDaughter: "youngerCousinParentsSiblingsDaughter",
    CNLabelContactRelationYoungerCousinParentsSiblingsSon: "youngerCousinParentsSiblingsSon",
    CNLabelContactRelationYoungerSibling: "youngerSibling",
    CNLabelContactRelationYoungerSiblingInLaw: "youngerSiblingInLaw",
    CNLabelContactRelationYoungerSister: "youngerSister",
    CNLabelContactRelationYoungerSisterInLaw: "youngerSisterInLaw",
    CNLabelContactRelationYoungestBrother: "youngestBrother",
    CNLabelContactRelationYoungestSister: "youngestSister"
  ]
}
