#!/usr/bin/env python3

import argparse
import logging
import colorama
import reccmp
from reccmp.compare import Compare
from reccmp.utils import print_combined_diff
from reccmp.project.logging import argparse_add_logging_args, argparse_parse_logging
from reccmp.project.detect import (
    argparse_add_project_target_args,
    argparse_parse_project_target,
    RecCmpProjectException,
)
from reccmp.compare.diff import CombinedDiffOutput

logger = logging.getLogger(__name__)

# Ignore all compare-db messages.
logging.getLogger("compare").addHandler(logging.NullHandler())

colorama.just_fix_windows_console()


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Comparing vtables.")
    parser.add_argument(
        "--version", action="version", version=f"%(prog)s {reccmp.VERSION}"
    )
    argparse_add_project_target_args(parser)
    parser.add_argument(
        "--verbose", "-v", action="store_true", help="Show more detailed information"
    )
    parser.add_argument(
        "--no-color", "-n", action="store_true", help="Do not color the output"
    )
    argparse_add_logging_args(parser)

    args = parser.parse_args()

    argparse_parse_logging(args)

    return args


def show_vtable_diff(udiff: CombinedDiffOutput, _: bool = False, plain: bool = False):
    print_combined_diff(udiff, plain)


def print_summary(vtable_count: int, problem_count: int):
    if problem_count == 0:
        print(f"Vtables found: {vtable_count}.\n100% match.")
        return

    print(f"Vtables found: {vtable_count}.\nVtables not matching: {problem_count}.")


def main():
    args = parse_args()
    vtable_count = 0
    problem_count = 0

    try:
        target = argparse_parse_project_target(args)
    except RecCmpProjectException as e:
        logger.error(e.args[0])
        return 1

    engine = Compare.from_target(target)

    for tbl_match in engine.compare_vtables():
        vtable_count += 1
        if tbl_match.ratio < 1:
            problem_count += 1

            udiff = tbl_match.udiff
            assert udiff is not None

            print(
                tbl_match.name,
                f": orig 0x{tbl_match.orig_addr:x}, recomp 0x{tbl_match.recomp_addr:x}",
            )
            show_vtable_diff(udiff, args.verbose, args.no_color)
            print()

    print_summary(vtable_count, problem_count)

    # Now compare adjuster thunk functions, if there are any.
    # These matches are generated by the compare engine.
    # They should always match 100%. If not, there is a problem
    # with the inheritance or an overriden function.
    for fun_match in engine.get_functions():
        assert fun_match.name is not None
        if "`vtordisp" not in fun_match.name:
            continue

        diff = engine.compare_address(fun_match.orig_addr)
        assert diff is not None
        if diff.ratio < 1.0:
            problem_count += 1
            print(
                f"Problem with adjuster thunk {fun_match.name} (0x{fun_match.orig_addr:x} / 0x{fun_match.recomp_addr:x})"
            )

    return 1 if problem_count > 0 else 0


if __name__ == "__main__":
    raise SystemExit(main())
