#!/usr/bin/env php
<?php declare(strict_types=1);
use ThreeEncr\TokenCrypt;

$autoloads = ['/../../../autoload.php', '/../vendor/autoload.php'];

foreach($autoloads as $autoload) {
    if (file_exists(__DIR__ .$autoload)) {
        require __DIR__ .$autoload;
        break;
    }
}

if ($argc == 2 && $argv[1] == '-h') {
    echo "Usage: ${argv[0]} [file with secrets]\n";
    echo "       if file not exists, tool tries to launch in interactive mode\n";
    echo "       supported file formats:\n";
    echo "       - 3 lines, 1st line - secret, 2nd line - salt, 3rd line - rounds\n";
    echo "       - 2 lines, 1st line ignored, 2nd line has secret, salt, rounds\n";
    echo "         separated by -@@-\n";
    exit(0);
}

$interactive = canInitInteractively();

if ($interactive && $argc === 1) {
    $tokenCrypt = initInteractive();
} else {
    if (!$interactive) {
        echo "Warning: unable to read passwords from terminal".PHP_EOL;
    }

    $file = $argc < 2 ? 'secrets.txt' : $argv[1];
    echo "Warning: reading file {$file} from command line".PHP_EOL;
    $tokenCrypt = initFromFile($file);
}


echo "Interactive session: press Ctrl-D or type q to quit".PHP_EOL;

while(1) {
    $line = readline("plain or encrypted text> ");
    if ($line === false) {
        exit(0);
    }
    
    $btrim = $line;
    $line = trim($line);
    if ($btrim != $line) {
        echo "warning: trimmed to '{$line}'".PHP_EOL;
    }

    if ($line == 'q') {
        exit(0);
    }
    if ($line == '') {
        echo "warning: empty string input".PHP_EOL;
        continue;
    }
    if (strpos($line, TokenCrypt::HEADER_V1) === 0) {
        $decr = $tokenCrypt->decrypt3ncr($line);
        if ($decr === false || $decr == $line) {
            echo "decryption error".PHP_EOL;
        } else {
            echo "decrypted plaintext: ".$decr.PHP_EOL;
        }
        continue;
    }

    echo "encrypted value: ".$tokenCrypt->encrypt3ncr($line)."\n";

}

function canInitInteractively(): bool {
    $result = shell_exec('/bin/stty -a');
    return is_string($result) && (strlen($result) > 1);
}

function tryInitFromSecretLine(string $line): ?TokenCrypt {
    // this is a special line to be stored in password manager 
    // it looks like the following
    // part1-@@-part2-@@-1000
    $parts = explode("-@@-", $line, 3);
    if (count($parts) != 3) {
        return null;
    }
    echo "Info: parsing secret line\n";
    if ((strlen($parts[0]) < 1)||(strlen($parts[1]) < 1)) {
        echo "Error: malformed secret-line - part1 or part2 too short\n";
        exit(1);
    }
    $iter = intval($parts[2]);
    if ($iter == 0) {
        echo "Error: malformed secret-line - bad iterations number\n";
        exit(1);
    }
    return new TokenCrypt($parts[0], $parts[1], $iter);
}

function initInteractive(): TokenCrypt {
    $part1 = getPassword('Enter secret part 1 (or secret line): ');
    $trySecretLine = tryInitFromSecretLine($part1);
    if (!is_null($trySecretLine)) {
        return $trySecretLine;
    }

    $part2 = getPassword('Enter secret part 2: ');

    while (1) {
        $iter = trim(readline("Enter iterations number (1000): "));
        if ($iter == '') {
            $iter = 1000;
        } else {
            $iter = intval($iter);
        }

        if ($iter == 0) {
            echo "error parsing integer\n";
            continue;
        }
        break;
    }

    return new TokenCrypt($part1, $part2, $iter);
}

function initFromFile($fileName): TokenCrypt {
    if (!file_exists($fileName)) {
        echo "file ${fileName} not exists\n";
        exit(1);
    }

    $fileData = trim(file_get_contents($fileName));
    $items = array_map('trim', explode("\n", $fileData));
    if (count($items) < 2) {
        echo "Error: bad or non-existent {$fileName}\n";
        exit(1);
    }
    $tokenTry = tryInitFromSecretLine($items[1]);
    if ($tokenTry !== null) {
        return $tokenTry; 
    }
    if (count($items) < 3) {
        echo "Warning: no iterations count specified, using 1000\n";
    }
    $iter = intval($items[2]);
    if ($iter == 0) {
        echo "Error: non-numeric or zero iterations count in secrets.txt: ".$items[2]."\n";
        exit(1);
    }

    return new TokenCrypt($items[0], $items[1], $iter);
}



function getPassword($prompt): string {
    echo $prompt;
    system('/bin/stty -echo');
    $password = trim(fgets(STDIN));
    system('/bin/stty echo');
    echo "\n";
    if ($password == '') {
        echo "Warning: empty password entered\n";
    }
    return $password;
}