//
// Created by Chris Bartley on 5/5/20.
//

import Foundation
import CoreBluetooth

// fileprivate struct Names: Decodable {
//    var badNames: [String]
//    var firstNames: [String]
//    var middleNames: [String]
//    var lastNames: [String]
//
//    enum CodingKeys: String, CodingKey {
//       case badNames = "bad_names"
//       case firstNames = "first_names"
//       case middleNames = "middle_names"
//       case lastNames = "last_names"
//    }
// }

class MemorableNameGenerator {
   static let instance = MemorableNameGenerator()

   func generateNameFrom(advertisementData: [String : Any]) -> (advertisedName: String?, name: String?) {
      if let advertisedName = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
         return (name: generateNameFrom(advertisedName: advertisedName), advertisedName: advertisedName)
      }
      return (advertisedName: nil, name: nil)
   }

   func generateNameFrom(advertisedName: String?) -> String? {
      if let advertisedName = advertisedName {
         // We generate the device name from the last five characters of the advertised name (those characters are
         // typically from the device's MAC address which is not available via Core Bluetooth.
         // See https://forums.developer.apple.com/thread/8442 for more info.
         if advertisedName.count >= 5 {
            let deviceName = advertisedName.suffix(5)

            // Treat as hex chars and convert to an Int, then we'll grab bits from the MAC address, like this:
            // (6 bits, 6 bits, 8 bits => last, middle, first)
            // (5 digis of mac address is 20 bits) llllllmmmmmmffffffff
            if let macNumber = Int(deviceName, radix: 16) {
               let offset = (macNumber & 0xFF) % 16
               let firstIndex = ((macNumber & 0xFF) + offset) % firstNames.count
               var middleIndex = (((macNumber >> 8) & 0b111111) + offset) % middleNames.count
               let lastIndex = (((macNumber >> (8 + 6)) & 0b111111) + offset) % lastNames.count

               let firstName = firstNames[firstIndex]
               var middleName = middleNames[middleIndex]
               let lastName = lastNames[lastIndex]

               let firstNamePrefix = firstName.prefix(1)
               let lastNamePrefix = lastName.prefix(1)

               var abbreviatedName = String(firstNamePrefix + middleName.prefix(1) + lastNamePrefix)
               while badNames[abbreviatedName] != nil {
                  middleIndex = (middleIndex + 1) % middleNames.count
                  middleName = middleNames[middleIndex]
                  abbreviatedName = String(firstNamePrefix + middleName.prefix(1) + lastNamePrefix)
               }

               return firstName + " " + middleName + " " + lastName
            }
         }
      }

      return nil
   }

   private init() {}

   // This is dumb and gross. But, Swift packages don't yet support resource files, so we can't read from a plist. Fix
   // this and load a plist using the commented out Decodable above (e.g. https://stackoverflow.com/a/48140217/703200)
   // (with bonus points for making badNames a [String:Bool] dictionary, for more efficient lookups) once we move to
   // Swift 5.3, which apparently will include support for resources in packages.  See here for more info:
   // * https://stackoverflow.com/questions/39815054/how-to-include-assets-resources-in-a-swift-package-manager-library
   // * https://forums.swift.org/t/se-0271-package-manager-resources/30730/74
   // * https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types

   private let badNames: [String : Bool] = [
      "ANL" : true,
      "ANS" : true,
      "ASS" : true,
      "AZN" : true,
      "BCH" : true,
      "CAC" : true,
      "CAK" : true,
      "CAQ" : true,
      "CLT" : true,
      "CNT" : true,
      "COC" : true,
      "COK" : true,
      "COQ" : true,
      "CUM" : true,
      "DCK" : true,
      "DIC" : true,
      "DIK" : true,
      "DIQ" : true,
      "DIX" : true,
      "DMN" : true,
      "DSH" : true,
      "DYC" : true,
      "DYK" : true,
      "DYQ" : true,
      "FAG" : true,
      "FAP" : true,
      "FCK" : true,
      "FCU" : true,
      "FGT" : true,
      "FKU" : true,
      "FOB" : true,
      "FQU" : true,
      "FTP" : true,
      "FUC" : true,
      "FUK" : true,
      "FUQ" : true,
      "FUX" : true,
      "GAI" : true,
      "GAY" : true,
      "GEI" : true,
      "GEY" : true,
      "GIZ" : true,
      "GUC" : true,
      "GUK" : true,
      "GUQ" : true,
      "GVR" : true,
      "GZZ" : true,
      "HOR" : true,
      "JAP" : true,
      "JEW" : true,
      "JIZ" : true,
      "JOO" : true,
      "JYZ" : true,
      "JZZ" : true,
      "KAC" : true,
      "KAK" : true,
      "KAQ" : true,
      "KIK" : true,
      "KKK" : true,
      "KLT" : true,
      "KNT" : true,
      "KOC" : true,
      "KOK" : true,
      "KOQ" : true,
      "KOX" : true,
      "KUM" : true,
      "KYC" : true,
      "KYK" : true,
      "KYQ" : true,
      "LCK" : true,
      "LIC" : true,
      "LIK" : true,
      "LIQ" : true,
      "LOL" : true,
      "LSD" : true,
      "MFF" : true,
      "MIC" : true,
      "MIK" : true,
      "MIQ" : true,
      "MLF" : true,
      "MUF" : true,
      "MYC" : true,
      "MYK" : true,
      "MYQ" : true,
      "NAD" : true,
      "NDS" : true,
      "NDZ" : true,
      "NGR" : true,
      "NIG" : true,
      "NUT" : true,
      "NWA" : true,
      "ORL" : true,
      "OPP" : true,
      "PCP" : true,
      "PHC" : true,
      "PHK" : true,
      "PHQ" : true,
      "PIS" : true,
      "PMS" : true,
      "PNS" : true,
      "POO" : true,
      "POT" : true,
      "PRC" : true,
      "PRK" : true,
      "PRN" : true,
      "PRQ" : true,
      "PSS" : true,
      "PSY" : true,
      "PUS" : true,
      "RAC" : true,
      "RAK" : true,
      "RAQ" : true,
      "RCK" : true,
      "SAC" : true,
      "SAK" : true,
      "SAQ" : true,
      "SCK" : true,
      "SEX" : true,
      "SFU" : true,
      "SHT" : true,
      "SJV" : true,
      "SLT" : true,
      "SNM" : true,
      "SOB" : true,
      "SOL" : true,
      "STD" : true,
      "SUC" : true,
      "SUK" : true,
      "SUQ" : true,
      "SXE" : true,
      "SXI" : true,
      "SXX" : true,
      "SXY" : true,
      "THC" : true,
      "TIT" : true,
      "TOC" : true,
      "TOK" : true,
      "TOQ" : true,
      "TWT" : true,
      "VAG" : true,
      "VAJ" : true,
      "VGN" : true,
      "VJN" : true,
      "WAC" : true,
      "WAK" : true,
      "WAQ" : true,
      "WCK" : true,
      "WOP" : true,
      "WTF" : true,
      "XTC" : true,
      "XXX" : true,
      "AZS" : true,
      "AZZ" : true
   ]

   private let firstNames: [String] = [
      "Adorable",
      "Adventurous",
      "Agile",
      "Amazing",
      "Ancient",
      "Artistic",
      "Astounding",
      "Athletic",
      "Awesome",
      "Beautiful",
      "Benevolent",
      "Big",
      "Blazing",
      "Blissful",
      "Blushing",
      "Bold",
      "Bouncy",
      "Breezy",
      "Bright",
      "Brilliant",
      "Bubbly",
      "Bumpy",
      "Busy",
      "Calm",
      "Camouflaged",
      "Carefree",
      "Caring",
      "Carnivorous",
      "Charming",
      "Cheerful",
      "Cheesy",
      "Classy",
      "Colossal",
      "Comfortable",
      "Cool",
      "Corny",
      "Courageous",
      "Cozy",
      "Crawling",
      "Crazy",
      "Creative",
      "Cuddly",
      "Cunning",
      "Dainty",
      "Dancing",
      "Dapper",
      "Daring",
      "Dark",
      "Dashing",
      "Delightful",
      "Deluxe",
      "Determined",
      "Doubtful",
      "Dreaming",
      "Dry",
      "Educated",
      "Elder",
      "Endearing",
      "Energetic",
      "Engaging",
      "Enormous",
      "Entertaining",
      "Exciting",
      "Extraordinary",
      "Fanciful",
      "Fantastic",
      "Fast",
      "Fearless",
      "Feathered",
      "Feisty",
      "Feral",
      "Fierce",
      "Floppy",
      "Fluffy",
      "Flying",
      "Friendly",
      "Frosty",
      "Funny",
      "Furry",
      "Fuzzy",
      "Galactic",
      "Gargantuan",
      "Generous",
      "Gentle",
      "Genuine",
      "Giant",
      "Giggly",
      "Ginormous",
      "Glacial",
      "Glamorous",
      "Gleeful",
      "Glistening",
      "Glittery",
      "Glossy",
      "Glowing",
      "Good",
      "Goofy",
      "Gorgeous",
      "Graceful",
      "Great",
      "Groovy",
      "Grumpy",
      "Gutsy",
      "Hairy",
      "Happy",
      "Heavy",
      "Helpful",
      "Heroic",
      "Hidden",
      "Hopeful",
      "Hopping",
      "Huge",
      "Humongous",
      "Humorous",
      "Hungry",
      "Hyper",
      "Icy",
      "Idealistic",
      "Imaginative",
      "Impressive",
      "Incredible",
      "Ingenious",
      "Inky",
      "Innovative",
      "Inspiring",
      "Intellectual",
      "Interesting",
      "Interstellar",
      "Intrepid",
      "Itty-Bitty",
      "Jazzy",
      "Jiggly",
      "Joking",
      "Jovial",
      "Joyful",
      "Jumpy",
      "Lacy",
      "Large",
      "Laughing",
      "Lazy",
      "Leafy",
      "Light",
      "Lively",
      "Long",
      "Loony",
      "Loud",
      "Lovely",
      "Loyal",
      "Lucky",
      "Lyrical",
      "Magical",
      "Magnetic",
      "Majestic",
      "Marvelous",
      "Masterful",
      "Mega",
      "Merry",
      "Metallic",
      "Micro",
      "Mighty",
      "Mini",
      "Mischievous",
      "Muscular",
      "Musical",
      "Mutant",
      "Mysterious",
      "Mythical",
      "Nice",
      "Nocturnal",
      "Noticeable",
      "Optimistic",
      "Outdoorsy",
      "Painted",
      "Patient",
      "Peaceful",
      "Perfect",
      "Persistent",
      "Pigmy",
      "Playful",
      "Polite",
      "Powerful",
      "Quick",
      "Quiet",
      "Quirky",
      "Random",
      "Remarkable",
      "Righteous",
      "Robotic",
      "Rockin'",
      "Rough",
      "Round",
      "Royal",
      "Running",
      "Scaly",
      "Scary",
      "Shadowy",
      "Shiny",
      "Shy",
      "Singing",
      "Skating",
      "Skeptical",
      "Skipping",
      "Sleepy",
      "Slippery",
      "Slow",
      "Small",
      "Smiling",
      "Sneezy",
      "Soaring",
      "Soft",
      "Sparkly",
      "Speckled",
      "Spikey",
      "Spirited",
      "Splendid",
      "Spooky",
      "Spotted",
      "Spunky",
      "Squeaky",
      "Squishy",
      "Starry",
      "Stealthy",
      "Stellar",
      "Stretchy",
      "Striped",
      "Strong",
      "Super",
      "Surprised",
      "Swimming",
      "Tall",
      "Tame",
      "Terrific",
      "Thorny",
      "Thundering",
      "Ticklish",
      "Tiny",
      "Traveling",
      "Tremendous",
      "Triumphant",
      "Truthful",
      "Twirling",
      "Ultra",
      "Unbelievable",
      "Velvety",
      "Visionary",
      "Vivacious",
      "Vivid",
      "Vocal",
      "Warm",
      "Wild",
      "Winged",
      "Wise",
      "Witty",
      "Wonderful",
      "Young",
      "Zealous"
   ]

   private let middleNames: [String] = [
      "Amber",
      "Amethyst",
      "Apricot",
      "Arboreal",
      "Arctic",
      "Banana",
      "Blue",
      "Brass",
      "Cave",
      "Celestial",
      "Citrine",
      "Cloud",
      "Cobalt",
      "Copper",
      "Crystal",
      "Desert",
      "Diamond",
      "Emerald",
      "Fire",
      "Forest",
      "Fuchsia",
      "Gold",
      "Gray",
      "Green",
      "Indigo",
      "Jade",
      "Jungle",
      "Lava",
      "Lavender",
      "Lightning",
      "Lime",
      "Magenta",
      "Maroon",
      "Moonstone",
      "Mountain",
      "Navy",
      "Ocean",
      "Olive",
      "Onyx",
      "Opal",
      "Orange",
      "Pearl",
      "Pink",
      "Platinum",
      "Plum",
      "Purple",
      "Quartz",
      "Rainforest",
      "Red",
      "River",
      "Ruby",
      "Sand",
      "Sapphire",
      "Scarlet",
      "Silver",
      "Sky",
      "Snow",
      "Space",
      "Tangerine",
      "Teal",
      "Titanium",
      "Topaz",
      "Violet",
      "Yellow"
   ]

   private let lastNames: [String] = [
      "Beaver",
      "Bee",
      "Canary",
      "Cat",
      "Catfish",
      "Centaur",
      "Chicken",
      "Coyote",
      "Cricket",
      "Dinosaur",
      "Dog",
      "Dolphin",
      "Dragon",
      "Dragonfly",
      "Eagle",
      "Elephant",
      "Falcon",
      "Flamingo",
      "Fox",
      "Giraffe",
      "Grasshopper",
      "Griffin",
      "Hamster",
      "Hawk",
      "Hippogriff",
      "Hippopotamus",
      "Horse",
      "Inchworm",
      "Kitten",
      "Kraken",
      "Lemur",
      "Leopard",
      "Lion",
      "Lizard",
      "Manatee",
      "Monkey",
      "Narwhal",
      "Octopus",
      "Parrot",
      "Phoenix",
      "Platypus",
      "Pony",
      "Porcupine",
      "Puppy",
      "Raccoon",
      "Rooster",
      "Seahorse",
      "Sloth",
      "Slug",
      "Snail",
      "Sphinx",
      "Squid",
      "Squirrel",
      "Stegosaurus",
      "Tiger",
      "Timberwolf",
      "Tuna",
      "Tyrannosaurus",
      "Unicorn",
      "Velociraptor",
      "Walrus",
      "Whale",
      "Wolf",
      "Zebra"
   ]
}

