use std::fs;

use z3::{Config, SatResult, Solver, ast::Int, with_z3_config};

const COLORS: u64 = 3;

fn main() {
    let numbers: Option<usize> = if let Some(numbers) = std::env::args().skip(1).next()
        && let Ok(numbers) = numbers.parse()
    {
        Some(numbers)
    } else {
        None
    };
    let mut config = Config::new();
    config.set_model_generation(true);
    with_z3_config(&config, || {
        for i in 1.. {
            let i = if let Some(numbers) = numbers {
                numbers
            } else {
                i
            };
            let solver = Solver::new();
            let nums: Vec<_> = (1..=i).map(|n| Int::new_const(n.to_string())).collect();
            nums.iter().for_each(|n| {
                solver.assert(&n.ge(0));
                solver.assert(&n.le(COLORS - 1));
            });
            for diff in (1..=nums.len().isqrt()).map(|n| n * n) {
                for j in 0..nums.len() - diff {
                    solver.assert(&nums[j].ne(&nums[j + diff]));
                }
            }
            match solver.check() {
                SatResult::Sat => {
                    println!("Works for {COLORS} colors and {i} numbers.");
                    if let Some(model) = solver.get_model() {
                        let model_str = model.to_string();
                        let mut model: Vec<_> = model_str.lines().collect();
                        model.sort_by_key(|line| {
                            line.split(" -> ").next().unwrap().parse::<u32>().unwrap()
                        });
                        fs::write(
                            format!("models/model-c{COLORS}-n{i}.txt"),
                            format!("{}", model.join("\n")),
                        )
                        .unwrap();
                    }
                }
                SatResult::Unsat => {
                    println!("Does not work for {COLORS} colors and {i} numbers.");
                    break;
                }
                SatResult::Unknown => {
                    println!("Unknown for {COLORS} colors and {i} numbers.");
                    break;
                }
            }
            if numbers.is_some() {
                break;
            }
        }
    });
}