<?php

namespace App\Console\Commands\Intuit;

use Illuminate\Console\Command;
use Intuit\Jobs\AccountingInvoiceUpdate;
use Intuit\Models\Invoice as AccInvoice;

use App\Models\{Invoice,ProviderOauth,User};

class InvoiceAdd extends Command
{
	private const provider = 'intuit';

	/**
	 * The name and signature of the console command.
	 *
	 * @var string
	 */
	protected $signature = 'accounting:invoice:add'
		.' {id : Invoice ID}'
		.' {user? : User Email}';

	/**
	 * The console command description.
	 *
	 * @var string
	 */
	protected $description = 'Add an invoice to the accounting provider';

	/**
	 * Execute the console command.
	 *
	 * @return int
	 * @throws \Exception
	 */
	public function handle()
	{
		$uo = User::where('email',$this->argument('user') ?: config('osb.admin'))->singleOrFail();

		$so = ProviderOauth::where('name',self::provider)->singleOrFail();
		if (! ($to=$so->token($uo)))
			abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));

		$o = Invoice::findOrFail($this->argument('id'));

		// Check the customer exists
		if ($o->account->providers->where('pivot.provider_oauth_id',$so->id)->count() !== 1)
			throw new \Exception(sprintf('Account [%d] for Invoice [%d] not defined',$o->account_id,$o->id));

		$ao = $o->account->providers->where('pivot.provider_oauth_id',$so->id)->pop();

		// Some validation
		if (! $ao->pivot->ref) {
			$this->error(sprintf('Accounting not defined for account [%d]',$o->account_id));
			exit(1);
		}

		$acc = new AccInvoice;
		$acc->CustomerRef = (object)['value'=>$ao->pivot->ref];
		$acc->DocNumber = $o->lid;
		$acc->TxnDate = $o->created_at->format('Y-m-d');
		$acc->DueDate = $o->due_at->format('Y-m-d');

		$lines = collect();
		$c = 0;

		// @todo Group these by ItemRef and the Same Unit Price and Description, so that we can then use quantity to represent the number of them.
		foreach ($o->items->groupBy(function($item) use ($so) {
			return sprintf('%s.%s.%s.%s',$item->item_type_name,$item->price_base,$item->product->provider_ref($so),$item->taxes->pluck('description')->join('|'));
		}) as $os)
		{
			$key = $os->first();

			// Some validation
			if (! ($ref=$key->product->provider_ref($so))) {
				$this->error(sprintf('Accounting not defined in product [%d]',$key->product_id));

				return self::FAILURE;
			}

			if ($key->taxes->count() !== 1) {
				$this->error(sprintf('Cannot handle when there is not just 1 tax line [%d]',$key->id));

				return self::FAILURE;
			}

			$c++;
			$line = new \stdClass;
			$line->Id = $c;
			$line->DetailType = 'SalesItemLineDetail';
			$line->Description = $key->item_type_name;
			$line->SalesItemLineDetail = (object)[
				'Qty' => $os->sum('quantity'),
				'UnitPrice' => $key->price_base,
				'ItemRef' => ['value'=>$ref],
				// @todo It is assumed there is only 1 tax category
				'TaxCodeRef' => ['value'=>$key->taxes->first()->tax->provider_ref($so)],
			];
			$line->Amount = $os->sum('quantity')*$key->price_base;

			$lines->push($line);
		}

		$acc->Line = $lines;

		return AccountingInvoiceUpdate::dispatchSync($to,$acc);
	}
}