use serde_json::{json, Value};

use crate::grid::Cell;
use crate::puzzle::Puzzle;

/// Serialize a puzzle to ipuz JSON format.
/// Spec: http://www.ipuz.org/
pub fn to_ipuz(puzzle: &Puzzle, title: &str) -> Value {
    let mut puzzle_grid = Vec::new();
    let mut solution_grid = Vec::new();

    // build cell number map
    let mut cell_numbers = std::collections::HashMap::new();
    for word in &puzzle.words {
        cell_numbers.entry((word.row, word.col)).or_insert(word.clue_number);
    }

    for r in 0..puzzle.height {
        let mut puzzle_row = Vec::new();
        let mut solution_row = Vec::new();
        for c in 0..puzzle.width {
            match puzzle.grid.get(r, c) {
                Cell::Black => {
                    puzzle_row.push(json!("#"));
                    solution_row.push(json!("#"));
                }
                Cell::Letter(ch) => {
                    let num = cell_numbers.get(&(r, c));
                    if let Some(&n) = num {
                        puzzle_row.push(json!(n));
                    } else {
                        puzzle_row.push(json!(0));
                    }
                    solution_row.push(json!(ch.to_string()));
                }
                Cell::Empty => {
                    let num = cell_numbers.get(&(r, c));
                    if let Some(&n) = num {
                        puzzle_row.push(json!(n));
                    } else {
                        puzzle_row.push(json!(0));
                    }
                    solution_row.push(json!(null));
                }
            }
        }
        puzzle_grid.push(puzzle_row);
        solution_grid.push(solution_row);
    }

    let across_clues: Vec<Value> = puzzle.clues_across.iter().map(|c| {
        json!([c.number, c.text])
    }).collect();

    let down_clues: Vec<Value> = puzzle.clues_down.iter().map(|c| {
        json!([c.number, c.text])
    }).collect();

    json!({
        "version": "http://ipuz.org/v2",
        "kind": ["http://ipuz.org/crossword#1"],
        "title": title,
        "dimensions": {
            "width": puzzle.width,
            "height": puzzle.height,
        },
        "puzzle": puzzle_grid,
        "solution": solution_grid,
        "clues": {
            "Across": across_clues,
            "Down": down_clues,
        },
        "difficulty": puzzle.difficulty_score,
    })
}
