//
//  HtmlService.swift
//  Padel Tournament
//
//  Created by Razmig Sarkissian on 25/10/2023.
//

import Foundation

enum HtmlService {
    
    case template(tournament: Tournament)
    case bracket(tournament: Tournament, roundIndex: Int)
    case match(match: Match)
    case player(entrant: TeamRegistration)
    case hiddenPlayer
    case groupstage(groupStage: GroupStage)
    case groupstageEntrant(entrant: TeamRegistration)
    case groupstageColumn(entrant: TeamRegistration, position: String)
    case groupstageRow(entrant: TeamRegistration, teamsPerBracket: Int)
    case groupstageScore(score: Match?, shouldHide: Bool)
    
    var url: URL {
        return URL(fileURLWithPath: "\(self.fileName)")
    }
        
    var fileName: String {
        switch self {
        case .template:
            return "tournament-template"
        case .bracket:
            return "bracket-template"
        case .match:
            return "match-template"
        case .player:
            return "player-template"
        case .hiddenPlayer:
            return "hiddenplayer-template"
        case .groupstage:
            return "groupstage-template"
        case .groupstageEntrant:
            return "groupstageentrant-template"
        case .groupstageRow:
            return "groupstagerow-template"
        case .groupstageColumn:
            return "groupstagecol-template"
        case .groupstageScore:
            return "groupstagescore-template"
        }
    }
    
    func html(headName: Bool, withRank: Bool, withScore: Bool) -> String {
        guard let file = Bundle.main.path(forResource: self.fileName, ofType: "html") else {
            fatalError()
        }
        
        guard let html = try? String(contentsOfFile: file, encoding: String.Encoding.utf8) else {
            fatalError()
        }
        
        switch self {
        case .groupstage(let bracket):
            var template = html
            if let startDate = bracket.startDate {
                template = template.replacingOccurrences(of: "{{bracketStartDate}}", with: startDate.formatted())
            } else {
                template = template.replacingOccurrences(of: "{{bracketStartDate}}", with: "")
            }
            template = template.replacingOccurrences(of: "{{tournamentTitle}}", with: bracket.tournamentObject()!.tournamentTitle(.short))
            template = template.replacingOccurrences(of: "{{bracketTitle}}", with: bracket.groupStageTitle())
            
            var col = ""
            var row = ""
            bracket.teams().forEach { entrant in
                col = col.appending(HtmlService.groupstageColumn(entrant: entrant, position: "col").html(headName: headName, withRank: withRank, withScore: withScore))
                row = row.appending(HtmlService.groupstageRow(entrant: entrant, teamsPerBracket: bracket.size).html(headName: headName, withRank: withRank, withScore: withScore))
            }
            template = template.replacingOccurrences(of: "{{teamsCol}}", with: col)
            template = template.replacingOccurrences(of: "{{teamsRow}}", with: row)
            
            return template
        case .groupstageEntrant(let entrant):
            var template = html
            if let playerOne = entrant.players()[safe: 0] {
                template = template.replacingOccurrences(of: "{{playerOne}}", with: playerOne.playerLabel())
                if withRank {
                    template = template.replacingOccurrences(of: "{{weightOne}}", with: "(\(playerOne.formattedRank()))")
                } else {
                    template = template.replacingOccurrences(of: "{{weightOne}}", with: "")
                }
            } else {
                template = template.replacingOccurrences(of: "{{playerOne}}", with: "--")
                template = template.replacingOccurrences(of: "{{weightOne}}", with: "")
            }
            
            if let playerTwo = entrant.players()[safe: 1] {
                template = template.replacingOccurrences(of: "{{playerTwo}}", with: playerTwo.playerLabel())
                if withRank {
                    template = template.replacingOccurrences(of: "{{weightTwo}}", with: "(\(playerTwo.formattedRank()))")
                } else {
                    template = template.replacingOccurrences(of: "{{weightTwo}}", with: "")
                }
            } else {
                template = template.replacingOccurrences(of: "{{playerTwo}}", with: "--")
                template = template.replacingOccurrences(of: "{{weightTwo}}", with: "")
            }
            return template
        case .groupstageRow(let entrant, let teamsPerBracket):
            var template = html
            template = template.replacingOccurrences(of: "{{team}}", with: HtmlService.groupstageColumn(entrant: entrant, position: "row").html(headName: headName, withRank: withRank, withScore: withScore))
            
            var scores = ""
            (0..<teamsPerBracket).forEach { index in
                let shouldHide = entrant.groupStagePosition! == index
                var match: Match? = nil
                if shouldHide == false {
                    match = entrant.groupStageObject()?.matchPlayed(by: entrant.groupStagePosition!, againstPosition: index)
                }
                scores.append(HtmlService.groupstageScore(score: match, shouldHide: shouldHide).html(headName: headName, withRank: withRank, withScore: withScore))
            }
            template = template.replacingOccurrences(of: "{{scores}}", with: scores)
            return template
        case .groupstageColumn(let entrant, let position):
            var template = html
            template = template.replacingOccurrences(of: "{{tablePosition}}", with: position)
            template = template.replacingOccurrences(of: "{{team}}", with: HtmlService.groupstageEntrant(entrant: entrant).html(headName: headName, withRank: withRank, withScore: withScore))
            return template
        case .groupstageScore(let match, let shouldHide):
            var template = html
            if match == nil || withScore == false {
                template = template.replacingOccurrences(of: "{{winner}}", with: "")
                template = template.replacingOccurrences(of: "{{score}}", with: "")
            } else {
                template = template.replacingOccurrences(of: "{{winner}}", with: match!.winner()!.teamLabel())
                template = template.replacingOccurrences(of: "{{score}}", with: match!.scoreLabel())
            }
            template = template.replacingOccurrences(of: "{{hide}}", with: shouldHide ? "hide" : "")
            return template
        case .player(let entrant):
            var template = html
            if let playerOne = entrant.players()[safe: 0] {
                template = template.replacingOccurrences(of: "{{playerOne}}", with: playerOne.playerLabel())
                if withRank {
                    template = template.replacingOccurrences(of: "{{weightOne}}", with: "(\(playerOne.formattedRank()))")
                } else {
                    template = template.replacingOccurrences(of: "{{weightOne}}", with: "")
                }
            } else {
                template = template.replacingOccurrences(of: "{{playerOne}}", with: "--")
                template = template.replacingOccurrences(of: "{{weightOne}}", with: "")
            }
            
            if let playerTwo = entrant.players()[safe: 1] {
                template = template.replacingOccurrences(of: "{{playerTwo}}", with: playerTwo.playerLabel())
                if withRank {
                    template = template.replacingOccurrences(of: "{{weightTwo}}", with: "(\(playerTwo.formattedRank()))")
                } else {
                    template = template.replacingOccurrences(of: "{{weightTwo}}", with: "")
                }
            } else {
                template = template.replacingOccurrences(of: "{{playerTwo}}", with: "--")
                template = template.replacingOccurrences(of: "{{weightTwo}}", with: "")
            }
            return template
        case .hiddenPlayer:
            return html + html
        case .match(let match):
            var template = html
            if let entrantOne = match.team(.one) {
                template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.player(entrant: entrantOne).html(headName: headName, withRank: withRank, withScore: withScore))
            } else {
                template = template.replacingOccurrences(of: "{{entrantOne}}", with: HtmlService.hiddenPlayer.html(headName: headName, withRank: withRank, withScore: withScore))
            }
            if let entrantTwo = match.team(.two) {
                template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.player(entrant: entrantTwo).html(headName: headName, withRank: withRank, withScore: withScore))
            } else {
                template = template.replacingOccurrences(of: "{{entrantTwo}}", with: HtmlService.hiddenPlayer.html(headName: headName, withRank: withRank, withScore: withScore))
            }
            if match.disabled {
                template = template.replacingOccurrences(of: "{{hidden}}", with: "hidden")
            } else {
                template = template.replacingOccurrences(of: "{{hidden}}", with: "")
            }
            if match.hasEnded() {
                if match.teamWon(atPosition: .one) == true {
                    template = template.replacingOccurrences(of: "{{entrantOneWon}}", with: "winner")
                } else if match.teamWon(atPosition: .two) == true {
                    template = template.replacingOccurrences(of: "{{entrantTwoWon}}", with: "winner")
                }
                template = template.replacingOccurrences(of: "{{matchDescription}}", with: [match.localizedStartDate(), match.scoreLabel()].joined(separator: "\n"))
            }
            template = template.replacingOccurrences(of: "{{matchDescription}}", with: "")
            return template
        case .bracket(let tournament, let roundIndex):
            var template = ""
            var bracket = ""
            if let round = tournament.rounds().first(where: { $0.index == roundIndex }) {
                for (_, match) in round._matches().enumerated() {
                    template = template.appending(HtmlService.match(match: match).html(headName: headName, withRank: withRank, withScore: withScore))
                }
                bracket = html.replacingOccurrences(of: "{{match-template}}", with: template)
                bracket = bracket.replacingOccurrences(of: "{{roundLabel}}", with: round.roundTitle())
            }
            return bracket
        case .template(let tournament):
            var template = html
            template = template.replacingOccurrences(of: "{{tournamentTitle}}", with: tournament.tournamentTitle(.short))
            var brackets = ""
            for round in tournament.rounds() {
                brackets = brackets.appending(HtmlService.bracket(tournament: tournament, roundIndex: round.index).html(headName: headName, withRank: withRank, withScore: withScore))
            }
            
            var winnerName = ""
            if let tournamentWinner = tournament.tournamentWinner() {
                winnerName = HtmlService.player(entrant: tournamentWinner).html(headName: headName, withRank: withRank, withScore: withScore)
            }
            let winner = """
            <ul class="round" scope="last">
                <li class="spacer">&nbsp;</li>
                <li class="game game-top winner">\(winnerName)</li>
                <li class="spacer">&nbsp;</li>
            </ul>
            <ul class="main" style="visibility:hidden">
            </ul>
            """
            brackets = brackets.appending(winner)

            template = template.replacingOccurrences(of: "{{brackets}}", with: brackets)
            return template
        }
    }
}
