package sudoku;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.util.Random;

import org.json.JSONObject;
import org.junit.jupiter.api.Test;

import sudoku.io.SudokuSerializer;
import sudoku.solver.RandomSolver;
import sudoku.structure.MultiDoku;
import sudoku.structure.SudokuFactory;

public class SudokuSerializerTest {

    void testSerializeWithSize(int blockWidth, int blockHeight) {
        var sudoku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight,
                SudokuFactory.DEFAULT_CONSTRAINTS);
        new RandomSolver().solve(sudoku);
        JSONObject data = SudokuSerializer.serializeSudoku(sudoku);
        MultiDoku multiDoku = SudokuSerializer.deserializeSudoku(data);
        assertTrue(data.toString().equals(SudokuSerializer.serializeSudoku(multiDoku).toString()));
    }

    void testSaveWithSize(int blockWidth, int blockHeight) {
        MultiDoku doku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight,
                SudokuFactory.DEFAULT_CONSTRAINTS);
        new RandomSolver().solve(doku);
        String savePath = SudokuSerializer.saveMultiDoku(doku);
        MultiDoku otherDoku = null;
        try {
            otherDoku = SudokuFactory.fromfile(savePath);
            assert (otherDoku != null);

            assertEquals(SudokuSerializer.serializeSudoku(doku).toString(),
                    SudokuSerializer.serializeSudoku(otherDoku).toString());
            // clean file after test
            File fileToDelete = new File(savePath);
            fileToDelete.delete();
        } catch (Exception e) {
            e.printStackTrace();
            assert false;
        }
    }

    void testSerializeX(int size) {
        var sudoku = SudokuFactory.createBasicXShapedMultidoku(size, SudokuFactory.DEFAULT_CONSTRAINTS);
        new RandomSolver().solve(sudoku);
        JSONObject data = SudokuSerializer.serializeSudoku(sudoku);
        MultiDoku multiDoku = SudokuSerializer.deserializeSudoku(data);

        assertTrue(data.toString().equals(SudokuSerializer.serializeSudoku(multiDoku).toString()));
    }

    @Test
    void testSerialize() {
        Random r = new Random();
        int testCount = 20;
        for (int i = 0; i < testCount; i++) {
            int blockWidth = r.nextInt(4) + 1;
            int blockHeight = r.nextInt(4) + 1;
            testSerializeWithSize(blockWidth, blockHeight);
        }
        for (int i = 0; i < testCount; i++) {
            int blockWidth = r.nextInt(4) + 1;
            int blockHeight = r.nextInt(4) + 1;
            testSaveWithSize(blockWidth, blockHeight);
        }
        for (int i = 0; i < testCount; i++) {
            int size = r.nextInt(2) + 2;
            testSerializeX(size);
        }
    }

}
