from __future__ import annotations

import shlex
import subprocess

import pytest

import hashImage


def hamming_distance(h1, h2) -> int:
    if isinstance(h1, int):
        n1 = h1
    else:
        n1 = int(h1, 2)

    if isinstance(h2, int):
        n2 = h2
    else:
        n2 = int(h2, 2)

    # xor the two numbers
    n = n1 ^ n2

    # count up the 1's in the binary string
    return bin(n)[2:].count('1')


def test_hash(request, file, record_property):
    hasher = request.config.getoption('--hasher')
    try:
        python = hashImage.main(['-file', file]) + '\n'
    except Exception:
        if request.config.getoption('--skip-invalid-image'):
            pytest.skip('python imagehash failed')
        return

    sh = shlex.shlex(hasher, punctuation_chars=True, posix=True)
    sh.whitespace_split = True
    cmd_list = list(sh)
    for i, p in enumerate(cmd_list):
        if p == '{}':
            cmd_list[i] = file

    external = subprocess.run(cmd_list, shell=None, capture_output=True)
    external_stdout = str(external.stdout, encoding='utf-8')
    if external.returncode != 0:
        if request.config.getoption('--skip-invalid-image'):
            pytest.skip(str(external.stderr))
        return

    external_stdout_h = python_h = ''
    for p, e in zip(python.splitlines(), external_stdout.splitlines()):
        p_, e_ = p.split(' '), e.split(' ')
        h = hamming_distance(p_[1], e_[1])
        record_property(p_[0], h)
        external_stdout_h += ' '.join(e_) + f' {h}\n'
        python_h += ' '.join(p_) + f' {h}\n'

    assert external_stdout_h == python_h
