package aoc2025

import println
import readInput
import splitInts
import java.util.*
import kotlin.math.abs

/*
--- Day 9: Movie Theater ---
https://adventofcode.com/2025/day/9
*/
fun main() {

    val inlineTestInput = """
7,1
11,1
11,7
9,7
9,5
2,5
2,3
7,3
"""

    fun part1(input: List<String>): Long {
        val coords = input.map { it.splitInts(",") }
        var maxArea = 0L
        for (i1 in 0 until coords.size step 2) {
            for (i2 in i1 + 2 until coords.size step 2) {
                maxArea =
                    ((abs(coords[i1][0] - coords[i2][0]) + 1).toLong() * (abs(coords[i1][1] - coords[i2][1]) + 1).toLong()).coerceAtLeast(
                        maxArea
                    )
            }
        }
        return maxArea
    }

    fun intersectsRanges(set: TreeMap<Int, ArrayList<IntRange>>, x1: Int, y1: Int, x2: Int, y2: Int) =
        set.subMap(y1 + 1, y2).values.any { it.any { it.first < x2 && it.last > x1 } }

    fun part2(input: List<String>): Long {
        val coords = input.map { it.splitInts(",") }
        val xSpans = TreeMap<Int, ArrayList<IntRange>>()
        val ySpans = TreeMap<Int, ArrayList<IntRange>>()
        for (i1 in 0 until coords.size) {
            val i2 = if (i1 != coords.size - 1) i1 + 1 else 0
            if (coords[i1][1] == coords[i2][1]) {
                xSpans.getOrPut(coords[i1][1]) { ArrayList<IntRange>() }.add(
                    IntRange(coords[i1][0].coerceAtMost(coords[i2][0]), coords[i1][0].coerceAtLeast(coords[i2][0]))
                )
            } else {
                ySpans.getOrPut(coords[i1][0]) { ArrayList<IntRange>() }.add(
                    IntRange(coords[i1][1].coerceAtMost(coords[i2][1]), coords[i1][1].coerceAtLeast(coords[i2][1]))
                )
            }
        }

        var maxArea = 0L
        for (i1 in 0 until coords.size step 2) {
            for (i2 in i1 + 2 until coords.size step 2) {
                val x1 = coords[i1][0].coerceAtMost(coords[i2][0])
                val x2 = coords[i1][0].coerceAtLeast(coords[i2][0])
                val y1 = coords[i1][1].coerceAtMost(coords[i2][1])
                val y2 = coords[i1][1].coerceAtLeast(coords[i2][1])

                val area = ((x2 - x1 + 1).toLong() * (y2 - y1 + 1).toLong())
                if (area > maxArea &&
                    !(intersectsRanges(xSpans, x1, y1, x2, y2) || intersectsRanges(ySpans, y1, x1, y2, x2))
                ) {
                    maxArea = area
                }
            }
        }
        return maxArea
    }

    // test if implementation meets criteria from the description, like:
    val testInput = inlineTestInput.trim().reader().readLines()
    //val testInput = readInput("aoc2025/Day09_test")
    val testInputPart1Result = part1(testInput)
    println("Part 1 Test: $testInputPart1Result")
    val testInputPart2Result = part2(testInput)
    println("Part 2 Test: $testInputPart2Result")
    check(testInputPart1Result == 50L)
    check(testInputPart2Result == 24L)
    val input = readInput("aoc2025/Day09")
    part1(input).println()
    part2(input).println()
}
