//
//  RomanTypographys.swift
//  Keyboard
//
//  Created by ensan on 2020/11/04.
//  Copyright © 2020 ensan. All rights reserved.
//

import Foundation
import SwiftUtils

private extension UnicodeScalar {
    /// ローマ字の大文字かどうか
    var isRomanUppercased: Bool {
        ("A"..."Z").contains(self)
    }
    /// ローマ字の小文字かどうか
    var isRomanLowercased: Bool {
        ("a"..."z").contains(self)
    }
    /// ローマ字の数字かどうか
    var isRomanNumber: Bool {
        ("0"..."9").contains(self)
    }
}

extension KanaKanjiConverter {
    /// 装飾文字に変換した結果を返す関数。
    /// - parameters:
    ///   - text: 対象文字列。
    /// - note:
    ///    現在英字のみ。ギリシャ文字や数字に対応する必要あり。
    func typographicalCandidates(_ inputData: ComposingText) -> [Candidate] {
        let string = inputData.convertTarget.toKatakana()
        let strings = self.typographicalLetters(from: string)
        return strings.map {
            Candidate(
                text: $0,
                value: -15,
                composingCount: .inputCount(inputData.input.count),
                lastMid: MIDData.一般.mid,
                data: [DicdataElement(word: $0, ruby: string, cid: CIDData.固有名詞.cid, mid: MIDData.一般.mid, value: -15)]
            )
        }
    }

    /// 装飾文字を実際に作る部分。
    /// - parameters:
    ///   - text: 対象文字列。
    private func typographicalLetters(from text: String) -> [String] {
        if !text.onlyRomanAlphabetOrNumber {
            return []
        }
        let onlyRomanAlphabet = text.onlyRomanAlphabet
        var strings: [String] = []
        /// 𝐁𝐎𝐋𝐃
        do {
            let bold = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 119743)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 119737)!
                    return String(scalar)
                }
                if $0.isRomanNumber {
                    let scalar = UnicodeScalar($0.value + 120734)!
                    return String(scalar)
                }
                return String($0)
            }.joined()
            strings.append(bold)
        }
        /// 𝐼𝑇𝐴𝐿𝐼𝐶
        if onlyRomanAlphabet {
            let italic = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 119795)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    if $0 == "h" {
                        return "ℎ"
                    }
                    let scalar = UnicodeScalar($0.value + 119789)!
                    return String(scalar)
                }
                return String($0)
            }.joined()
            strings.append(italic)
        }
        /// 𝑩𝑶𝑳𝑫𝑰𝑻𝑨𝑳𝑰𝑪
        if onlyRomanAlphabet {
            let boldItalic = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 119847)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 119841)!
                    return String(scalar)
                }
                return String($0)
            }.joined()
            strings.append(boldItalic)
        }

        /// 𝒮𝒸𝓇𝒾𝓅𝓉
        if onlyRomanAlphabet {
            let script = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    switch $0 {
                    case "B":
                        return "ℬ"
                    case "E":
                        return "ℰ"
                    case "F":
                        return "ℱ"
                    case "H":
                        return "ℋ"
                    case "I":
                        return "ℐ"
                    case "L":
                        return "ℒ"
                    case "M":
                        return "ℳ"
                    case "R":
                        return "ℛ"
                    default:
                        break
                    }

                    let scalar = UnicodeScalar($0.value + 119899)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    switch $0 {
                    case "e":
                        return "ℯ"
                    case "g":
                        return "ℊ"
                    case "o":
                        return "ℴ"
                    default: break
                    }
                    let scalar = UnicodeScalar($0.value + 119893)!
                    return String(scalar)
                }
                return String($0)
            }.joined()
            strings.append(script)
        }

        /// 𝓑𝓸𝓵𝓭𝓢𝓬𝓻𝓲𝓹𝓽
        if onlyRomanAlphabet {
            let boldScript = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 119951)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 119945)!
                    return String(scalar)
                }
                return String($0)
            }.joined()
            strings.append(boldScript)
        }
        /// 𝔉𝔯𝔞𝔨𝔱𝔲𝔯
        if onlyRomanAlphabet {
            let fraktur = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    switch $0 {
                    case "C":
                        return "ℭ"
                    case "H":
                        return "ℌ"
                    case "I":
                        return "ℑ"
                    case "R":
                        return "ℜ"
                    case "Z":
                        return "ℨ"
                    default: break
                    }
                    let scalar = UnicodeScalar($0.value + 120003)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 119997)!
                    return String(scalar)
                }
                return String($0)
            }.joined()
            strings.append(fraktur)
        }

        /// 𝕕𝕠𝕦𝕓𝕝𝕖𝕊𝕥𝕣𝕦𝕔𝕜
        do {
            let doubleStruck = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    switch $0 {
                    case "C":
                        return "ℂ"
                    case "H":
                        return "ℍ"
                    case "N":
                        return "ℕ"
                    case "P":
                        return "ℙ"
                    case "Q":
                        return "ℚ"
                    case "R":
                        return "ℝ"
                    case "Z":
                        return "ℤ"
                    default: break
                    }
                    let scalar = UnicodeScalar($0.value + 120055)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 120049)!
                    return String(scalar)
                }
                if $0.isRomanNumber {
                    let scalar = UnicodeScalar($0.value + 120744)!
                    return String(scalar)
                }
                return String($0)
            }.joined()
            strings.append(doubleStruck)
        }

        /// 𝕭𝖔𝖑𝖉𝕱𝖗𝖆𝖐𝖙𝖚𝖗
        if onlyRomanAlphabet {
            let boldFraktur = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 120107)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 120101)!
                    return String(scalar)
                }
                return String($0)
            }.joined()

            strings.append(boldFraktur)
        }

        /// 𝖲𝖺𝗇𝗌𝖲𝖾𝗋𝗂𝖿
        do {
            let sansSerif = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 120159)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 120153)!
                    return String(scalar)
                }
                if $0.isRomanNumber {
                    let scalar = UnicodeScalar($0.value + 120754)!
                    return String(scalar)
                }
                return String($0)
            }.joined()
            strings.append(sansSerif)
        }

        /// 𝗦𝗮𝗻𝘀𝗦𝗲𝗿𝗶𝗳𝗕𝗼𝗹𝗱
        do {
            let sansSerifBold = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 120211)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 120205)!
                    return String(scalar)
                }
                if $0.isRomanNumber {
                    let scalar = UnicodeScalar($0.value + 120764)!
                    return String(scalar)
                }
                return String($0)
            }.joined()

            strings.append(sansSerifBold)
        }

        /// 𝘚𝘢𝘯𝘴𝘚𝘦𝘳𝘪𝘧𝘐𝘵𝘢𝘭𝘪𝘤
        if onlyRomanAlphabet {
            let sansSerifItalic = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 120263)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 120257)!
                    return String(scalar)
                }
                return String($0)
            }.joined()

            strings.append(sansSerifItalic)
        }

        /// 𝙎𝙖𝙣𝙨𝙎𝙚𝙧𝙞𝙛𝘽𝙤𝙡𝙙𝙄𝙩𝙖𝙡𝙞𝙘
        if onlyRomanAlphabet {
            let sansSerifBoldItalic = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 120315)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 120309)!
                    return String(scalar)
                }
                return String($0)
            }.joined()

            strings.append(sansSerifBoldItalic)
        }

        /// 𝙼𝚘𝚗𝚘𝚜𝚙𝚊𝚌𝚎
        do {
            let monospace = text.unicodeScalars.map {
                if $0.isRomanUppercased {
                    let scalar = UnicodeScalar($0.value + 120367)!
                    return String(scalar)
                }
                if $0.isRomanLowercased {
                    let scalar = UnicodeScalar($0.value + 120361)!
                    return String(scalar)
                }
                if $0.isRomanNumber {
                    let scalar = UnicodeScalar($0.value + 120774)!
                    return String(scalar)
                }
                return String($0)
            }.joined()

            strings.append(monospace)
        }

        return strings
    }
}
