#!/usr/bin/env php
<?php

use Joli\JoliNotif\Notification;
use Joli\JoliNotif\NotifierFactory;

if (file_exists(__DIR__ . '/vendor/autoload.php')) {
    $loader = require(__DIR__ . '/vendor/autoload.php');
} elseif (file_exists(__DIR__ . '/../../../vendor/autoload.php')) {
    $loader = require(__DIR__ . '/../../../vendor/autoload.php');
} else {
    throw new \RuntimeException('Unable to load autoloader.');
}

final class Cli
{
    const DESCRIPTION = 'Send notifications to your desktop directly from your terminal.';

    const RULES = [
        'title'    => [
            'name'     => 'title',
            'info'     => 'Notification title.',
            'required' => true,
        ],
        'body'     => [
            'name'     => 'body',
            'info'     => 'Notification body.',
            'required' => true,
        ],
        'icon'     => [
            'name'     => 'icon',
            'info'     => 'Notification icon.',
            'required' => false,
        ],
        'subtitle' => [
            'name'     => 'subtitle',
            'info'     => 'Notification subtitle. Only works on macOS (AppleScriptNotifier).',
            'required' => false,
        ],
        'sound'    => [
            'name'     => 'sound',
            'info'     => 'Notification sound. Only works on macOS (AppleScriptNotifier).',
            'required' => false,
        ],
        'url'      => [
            'name'     => 'url',
            'info'     => 'Notification url. Only works on macOS (TerminalNotifierNotifier).',
            'required' => false,
        ],
        'help'     => [
            'name' => 'help',
            'info' => 'Show this help.',
            'required' => false,
            'flag' => true,
        ],
    ];

    private $arguments = [];
    private $command = [];

    public function __construct()
    {
        $this->command = $_SERVER['argv'][0];
    }

    public function parse()
    {
        $options = '';
        $longOptions = array_map(function ($rule) {
            $flag = $rule['required'] ? ':' : '::';

            return $rule['name'] . $flag;
        }, self::RULES);

        $this->arguments = getopt($options, $longOptions) ?: [];
    }

    public function getOption(string $name)
    {
        return $this->arguments[$name] ?: false;
    }

    public function hasOption(string $name)
    {
        return isset($this->arguments[$name]);
    }

    public function validate()
    {
        $valid = true;

        foreach (self::RULES as $rule) {
            if ($rule['required'] && !$this->hasOption($rule['name'])) {
                $this->log("Please specify notification {$rule['name']} with the option --{$rule['name']}");
                $valid = false;
            }
        }

        return $valid;
    }

    public function showUsage()
    {
        $required = [];
        $optional = [];
        $usage = $this->command;

        foreach (self::RULES as $name => $rule) {
            $prefix = $postfix = '';
            if ($rule['required']) {
                $required[$name] = $rule;
            } else {
                $optional[$name] = $rule;
                $prefix = '[';
                $postfix = ']';
            }
            $usage .= ' ' . $prefix . $this->formatUsage($name, $rule) . $postfix;
        }

        $this->log(self::DESCRIPTION);
        $this->log(PHP_EOL . 'Usage: ' . trim($usage));

        $this->log(PHP_EOL . 'Required Arguments:');
        foreach ($required as $name => $info) {
            $value = $this->formatUsage($name, $info);
            $this->log("\t{$value}");
            $this->log("\t\t{$info['info']}");
        }

        $this->log(PHP_EOL . 'Optional Arguments:');
        foreach ($optional as $name => $info) {
            $value = $this->formatUsage($name, $info);
            $this->log("\t{$value}");
            $this->log("\t\t{$info['info']}");
        }
    }

    public function log(string $message)
    {
        echo $message . PHP_EOL;
    }

    private function formatUsage($name, $rule)
    {
        $example = $rule['required'] ? " {$name}" : "=\"{$name}\"";
        $value = isset($rule['flag']) && $rule['flag'] ? '' : $example;

        return '--' . $name . $value;
    }
}

$cli = new Cli();

try {
    $cli->parse();
} catch (Exception $e) {
    $cli->log($e->getMessage());
    exit(1);
}

if ($cli->hasOption('help')) {
    $cli->showUsage();
    exit(0);
}

if (!$cli->validate()) {
    exit(1);
}

$notifier = NotifierFactory::create();

$notification = (new Notification())
    ->setTitle($cli->getOption('title'))
    ->setBody($cli->getOption('body'));

if ($cli->hasOption('icon')) {
    $notification->setIcon($cli->getOption('icon'));
}

if ($cli->hasOption('subtitle')) {
    $notification->addOption('subtitle', $cli->getOption('subtitle'));
}

if ($cli->hasOption('sound')) {
    $notification->addOption('sound', $cli->getOption('sound'));
}

if ($cli->hasOption('url')) {
    $notification->addOption('url', $cli->getOption('url'));
}

$notifier->send($notification);
