package before.test.problem3

import java.time.LocalTime
import java.time.format.DateTimeFormatter
import kotlin.math.abs

class Solution3 {

    companion object {
        private const val SPLIT_OF_TIME = ":"
        private const val SPLIT_OF_TIME_RANGE = "~"
        private const val DAY_TO_HOUR = 24
        private const val END_OF_HOUR = 23
        private const val HOUR_TO_MINUTES = 60
        private const val END_OF_MINUTES = 59
        private const val TIME_FORMAT = "HH:mm"

        private const val START_HOUR = 0
        private const val START_MINUTES = 0
        private const val FAILED_FLAG = "impossible"
    }

    var disturbTime = Array(DAY_TO_HOUR) { BooleanArray(HOUR_TO_MINUTES) { false } }

    fun solution(noti_time: String, do_not_distrub: Array<String>): String {

        do_not_distrub.forEach { times ->
            val (startTime, endTime) = times.split(SPLIT_OF_TIME_RANGE)
            val (startHour, startMinutes) = startTime.split(SPLIT_OF_TIME).map { it.toInt() }
            val (endHour, endMinutes) = endTime.split(SPLIT_OF_TIME).map { it.toInt() }

            val startTotalMinutes = startHour * HOUR_TO_MINUTES + startMinutes
            val endTotalMinutes = endHour * HOUR_TO_MINUTES + endMinutes

            if (startTotalMinutes > endTotalMinutes) {
                setDisturbTime(startHour, startMinutes, END_OF_HOUR, HOUR_TO_MINUTES)
                setDisturbTime(START_HOUR, START_MINUTES, endHour, endMinutes)
                disturbTime[END_OF_HOUR][END_OF_MINUTES] = true
                disturbTime[START_HOUR][START_MINUTES] = true
            } else {
                setDisturbTime(startHour, startMinutes, endHour, endMinutes)
            }
        }

        val notiTime = noti_time.split(SPLIT_OF_TIME)
        val (notiHour, notiMinutes) = notiTime.map { it.toInt() }
        val notiTotal = notiHour * HOUR_TO_MINUTES + notiMinutes

        var answerHour = 0
        var answerMinutes = 0

        var answerTotalMin = Int.MAX_VALUE

        for (hour in notiHour..END_OF_HOUR) {
            val startMin = if (hour == notiHour) notiMinutes else 0
            for (minutes in startMin..END_OF_MINUTES) {
                if (!disturbTime[hour][minutes]) {
                    val totalMin = hour * HOUR_TO_MINUTES + minutes

                    val tempTotalMin = abs(totalMin - notiTotal)

                    if (tempTotalMin < answerTotalMin) {
                        answerHour = hour
                        answerMinutes = minutes
                        answerTotalMin = tempTotalMin
                    }
                }
            }
        }

        if (answerTotalMin != Int.MAX_VALUE) {
            return convertTimeFormatting(answerHour, answerMinutes)
        }

        for (hour in 0..END_OF_HOUR) {
            for (minutes in 0..END_OF_MINUTES) {
                if (!disturbTime[hour][minutes]) {
                    answerHour = hour
                    answerMinutes = minutes
                    return convertTimeFormatting(answerHour, answerMinutes)
                }
            }
        }

        return FAILED_FLAG
    }

    private fun setDisturbTime(startHour: Int, startMin: Int, endHour: Int, endMinutes: Int) {
        for (min in startMin until if (startHour == endHour) endMinutes else HOUR_TO_MINUTES) {
            disturbTime[startHour][min] = true
        }

        for (hour in startHour + 1..endHour) {
            val end = if (hour == endHour) endMinutes else HOUR_TO_MINUTES
            for (min in 0 until end) {
                disturbTime[hour][min] = true
            }
        }
    }


    private fun convertTimeFormatting(hour: Int, min: Int): String {
        val dateTimeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern(TIME_FORMAT)
        return dateTimeFormatter.format(LocalTime.of(hour, min))
    }
}