#!/usr/bin/python3
# encoding=utf-8
#
# Copyright © 2015 Simon McVittie <smcv@debian.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# You can find the GPL license text on a Debian system under
# /usr/share/common-licenses/GPL-2.

import difflib
import json
import os
import sys
import time
import yaml
from contextlib import suppress

if 'GDP_UNINSTALLED' not in os.environ:
    sys.path.insert(0, '/usr/share/game-data-packager')
    sys.path.insert(0, '/usr/share/games/game-data-packager')

from game_data_packager.game import (load_games, load_game)
from game_data_packager.util import ascii_safe

def dump(serialized):
    return json.dumps(serialized, sort_keys=True, indent=2)

def yaml_dump(serialized):
    return yaml.dump(serialized, default_flow_style=False)

def compare(
        to_data, to_json, label,
        expected_data, expected_json, expected_label):
    if to_json == expected_json:
        return True

    to_yaml = yaml_dump(to_data)
    expected_to_yaml = yaml_dump(expected_data)

    if to_yaml == expected_to_yaml:
        print('# JSON differs but YAML is the same?!')
        sys.stdout.writelines(difflib.unified_diff(
            to_json.splitlines(True),
            expected_json.splitlines(True),
            label, expected_label, n=50))
    else:
        sys.stdout.writelines(difflib.unified_diff(
            to_yaml.splitlines(True),
            expected_to_yaml.splitlines(True),
            label, expected_label, n=50))

    return False

if __name__ == '__main__':
    games = '*'

    if 'DEB_BUILD_TIME_TESTS' in os.environ:
        print('# SKIP: not doing memory-hungry test at build-time')
        sys.exit(0)

    if len(sys.argv) > 1:
        assert len(sys.argv) == 2
        games = sys.argv[1]

    if os.path.exists('ref.zip'):
        t = time.process_time()
        # usage:
        # make
        # cp out/vfs.zip ref.zip
        # make
        # make check
        from_ref = load_games(games, use_vfs='ref.zip')
        dt = time.process_time() - t
        print('# loaded game data from ref.zip in %.3f seconds' % dt, flush=True)
    else:
        from_ref = None

    t = time.process_time()
    from_vfs = load_games(games)
    dt = time.process_time() - t
    print('# loaded game data from vfs.zip in %.3f seconds' % dt, flush=True)

    t = time.process_time()
    from_json = load_games(games, use_vfs=False)
    dt = time.process_time() - t
    print('# loaded game data from JSON in %.3f seconds' % dt, flush=True)

    t = time.process_time()
    from_yaml = load_games(games, datadir='data', use_vfs=False)
    dt = time.process_time() - t
    print('# loaded game data from YAML in %.3f seconds' % dt)

    assert set(from_vfs.keys()) == set(from_json.keys())
    assert set(from_vfs.keys()) == set(from_yaml.keys())

    if from_ref is not None:
        assert set(from_vfs.keys()) == set(from_ref.keys())

    fail = False

    for (name, game) in sorted(from_vfs.items()):
        print('# %s -----------------------------------------' % name)

        with suppress(FileNotFoundError):
            os.remove('out/%s-unexpanded-yaml.txt' % name)

        # Do this one without checking consistency, so that we can assert
        # that skipping the consistency checks does not affect the outcome
        game.load_file_data(check=False)
        ascii_safe(game.longname, force=True).encode('ascii')
        ascii_safe(game.help_text, force=True).encode('ascii')
        vfs_to_data = game.to_data()
        vfs_to_json = dump(vfs_to_data)

        json_game = from_json[name]
        json_game.load_file_data(check=True, use_vfs=False)
        json_to_data = json_game.to_data()
        json_to_json = dump(json_to_data)
        json_to_data_unexpanded = json_game.to_data(
                expand=False, include_ignorable=True)
        json_to_json_unexpanded = dump(json_to_data_unexpanded)

        yaml_game = from_yaml[name]
        yaml_game.load_file_data(check=True, datadir='data')
        yaml_to_data = yaml_game.to_data()
        yaml_to_json = dump(yaml_to_data)

        if not compare(
                yaml_to_data, yaml_to_json, '%s loaded from YAML' % name,
                vfs_to_data, vfs_to_json, '%s loaded from vfs.zip' % name):
            fail = True

        if not compare(
                json_to_data, json_to_json, '%s loaded from JSON' % name,
                vfs_to_data, vfs_to_json, '%s loaded from vfs.zip' % name):
            fail = True

        if from_ref is not None:
            ref_game = from_ref[name]
            ref_game.load_file_data(use_vfs='ref.zip')
            ref_to_data = ref_game.to_data()
            ref_to_json = dump(ref_to_data)

            compare(
                ref_to_data, ref_to_json, '%s loaded from ref.zip' % name,
                vfs_to_data, vfs_to_json, '%s loaded from vfs.zip' % name)

        with open('out/%s-derived.txt' % name, 'w') as writer:
            writer.write(vfs_to_json)

        with open('out/%s-unexpanded.txt' % name, 'w') as writer:
            writer.write(json_to_json_unexpanded)

        # JSON is a subset of YAML so we can treat this as if YAML
        json_to_json_game = load_game(
            False, 'out/%s-unexpanded.txt' % name,
            None, name=name, yaml_file='out/%s-unexpanded.txt' % name)
        json_to_json_game.load_file_data()

        json_to_json_to_data = json_to_json_game.to_data()
        json_to_json_to_json = dump(json_to_json_to_data)

        if not compare(
            json_to_json_to_data, json_to_json_to_json,
            '%s loaded from unexpanded YAML' % name,
            vfs_to_data, vfs_to_json, '%s loaded from vfs.zip' % name):

            with open('out/%s-unexpanded-yaml.txt' % name, 'w') as writer:
                writer.write(yaml_dump(json_to_data_unexpanded))

            fail = True

    raise SystemExit(fail)
