package main

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

type Report struct {
	number    int
	levels    []int
	valid     bool
	direction string
	flag      int
	dampened  bool
}

// Reports stored one per line with levels in each column.
// In safe reports, the levels are either all increasing or all decreasing AND
// Any two adjacent levels differ by at least one and at most three.
func main() {
	input, err := os.ReadFile("input")
	if err != nil {
		fmt.Println(err)
	}
	var reports []Report

	lines := strings.Split(string(input), "\n")
	for idx, val := range lines[0 : len(lines)-1] {
		reportFields := strings.Fields(val)
		report := Report{
			number:    idx,
			valid:     true,
			direction: "ASC",
			flag:      -1,
			dampened:  false,
		}
		for _, field := range reportFields {
			reportVal, err := strconv.Atoi(field)
			if err != nil {
				break
			}

			report.levels = append(report.levels, reportVal)
		}
		reports = append(reports, report)
	}

	var valid int
	for _, report := range reports {
		if report.IsValid() {
			valid++
		}
		fmt.Printf("%v\n", report)
	}

	fmt.Printf("Total: %v Valid %v\n", len(reports), valid)
}

func (report *Report) IsValid() bool {
	if report.flag > 0 {
		report.dampened = true
	}

	// Determine direction
	if len(report.levels) >= 1 {
		report.direction = DetermineDirection(report.levels[0], report.levels[1])
		report.valid = report.ValidDirection() && report.ValidDeltas()
	}

	if !report.valid && report.flag > 0 && !report.dampened {
		fmt.Printf("DAMPING:%v\n", report.levels)
		report.levels = remove(report.levels, report.flag)
		fmt.Printf("DAMPING:%v\n", report.levels)
		return report.IsValid()
	}
	return report.valid
}

func remove(slice []int, s int) []int {
	return append(slice[:s], slice[s+1:]...)
}

func (report *Report) ValidDeltas() bool {
	for idx, val := range report.levels {
		if prev := idx - 1; prev < 0 {
			continue
		}
		last := report.levels[idx-1]
		delta := Abs(val - last)
		if delta < 1 || delta > 3 {
			report.flag = idx
			return false
		}
	}
	return true
}

func (report *Report) ValidDirection() bool {
	for idx, val := range report.levels {
		if prev := idx - 1; prev < 0 {
			continue
		}
		last := report.levels[idx-1]
		switch report.direction {
		case "ASC":
			if last > val {
				report.flag = idx
				return false
			}
		case "DESC":
			if last < val {
				report.flag = idx
				return false
			}
		default:
			panic("aaaaaa")
		}
	}
	return true
}

func DetermineDirection(one, two int) string {
	diff := one - two
	if diff < 0 {
		return "ASC"
	}
	return "DESC"
}

func Abs(input int) int {
	if input < 0 {
		return -input
	}
	return input
}