<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;

use App\Models\{Account,
	Charge,
	Invoice,
	InvoiceItem,
	Payment,
	PaymentItem,
	Service,
	SiteDetail,
	Supplier,
	SupplierDetail};

/**
 * The AdminController governs all routes that are prefixed with 'a/'.
 *
 * This is everything about the configuration of the application as a whole, or administration of a site.
 */
class AdminController extends Controller
{
	// @todo Move to reseller
	public function service(Service $o)
	{
		return View('a.service',['o'=>$o]);
	}

	// @todo Move to reseller
	public function charge_addedit(Request $request,Charge $o)
	{
		if ($request->post()) {
			$request->validate([
				'account_id' => 'required|exists:accounts,id',
				'charge_at' => 'required|date',
				'service_id' => 'required|exists:services,id',
				'quantity' => 'required|numeric|not_in:0',
				'amount' => 'required|numeric|min:0.01',
				'sweep_type' => 'required|numeric|in:'.implode(',',array_keys(Charge::sweep)),
				'type' => 'required|numeric|in:'.implode(',',array_keys(InvoiceItem::type)),
				'taxable' => 'nullable|boolean',
				'description' => 'nullable|string|max:128',
			]);

			if (! $o->exists) {
				$o->site_id = config('site')->site_id;
				$o->user_id = Auth::id();
				$o->active = TRUE;
			}

			$o->forceFill($request->only(['account_id','charge_at','service_id','quantity','amount','sweep_type','type','taxable','description']));
			$o->save();

			return redirect()->back()
				->with('success','Charge recorded: '.$o->id);
		}

		return view('a.charge.addedit')
			->with('o',$o);
	}

	// @todo Move to reseller
	public function charge_pending_account(Request $request,Account $o)
	{
		return view('a.charge.widgets.pending')
			->with('list',$o->charges->where('active',TRUE)->where('processed',NULL)->except($request->exclude));
	}

	/**
	 * List unprocessed charges
	 *
	 * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
	 */
	// @todo Move to reseller
	public function charge_unprocessed()
	{
		return view('a.charge.unprocessed');
	}

	/**
	 * Record payments on an account.
	 *
	 * @param Request $request
	 * @param Payment $o
	 * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
	 */
	// @todo Move to reseller
	public function pay_addedit(Request $request,Payment $o)
	{
		if ($request->post()) {

			$validation = $request->validate([
				'account_id' => 'required|exists:accounts,id',
				'paid_at' => 'required|date',
				'checkout_id' => 'required|exists:checkouts,id',
				'total_amt' => 'required|numeric|min:0.01',
				'fees_amt' => 'nullable|numeric|lt:total_amt',
				'source_id' => 'nullable|exists:accounts,id',
				'pending' => 'nullable|boolean',
				'notes' => 'nullable|string',
				'ip' => 'nullable|ip',
				'invoices' => ['required','array',function ($attribute,$value,$fail) use ($request) {
					if (collect($value)->sum('id') > $request->post('total_amt'))
						$fail('Allocation is greater than payment total.');
				}],
				'invoices.*.id' => ['required',function ($attribute,$value,$fail) {
					if (! Invoice::exists(str_replace(str_replace($attribute,'invoice\.','',),'.id','')))
						$fail('Invoice doesnt exist in DB');
				}],
			]);

			if (! $o->exists) {
				$o->site_id = config('site')->site_id;
				$o->active = TRUE;
			}

			$o->forceFill($request->only(['account_id','paid_at','checkout_id','total_amt','fees_amt','source_id','pending','notes','ip']));
			$o->save();

			foreach ($validation['invoices'] as $id => $amount) {
				// See if we already have a payment item that we need to update
				$items = $o->items->filter(function($item) use ($id) { return $item->invoice_id == $id; });

				if ($items->count() == 1) {
					$oo = $items->pop();
					if ($amount['id'] == 0) {
						$oo->delete();
						continue;
					}

				} else {
					$oo = new PaymentItem;
					$oo->invoice_id = $id;
				}

				$oo->amount = ($oo->invoice->due >= 0) && ($oo->invoice->due-$amount['id'] >= 0) ? $amount['id'] : 0;

				// If the amount is empty, ignore it.
				if (! $oo->amount)
					continue;

				$oo->site_id = config('site')->site_id;
				$oo->active = TRUE;
				$o->items()->save($oo);
			}

			return redirect()->back()
				->with('success','Payment recorded: '.$o->id);
		}

		return view('a.payment.addedit')
			->with('o',$o);
	}

	/**
	 * List unapplied payments
	 *
	 * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
	 */
	// @todo Move to reseller
	public function pay_unapplied()
	{
		return view('a.payment.unapplied');
	}

	/**
	 * Show a list of invoices to apply payments to
	 *
	 * @param Request $request
	 * @param Account $o
	 * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
	 */
	// @todo Move to reseller
	public function pay_invoices(Request $request,Account $o)
	{
		return view('a.payment.widgets.invoices')
			->with('pid',$request->pid)
			->with('o',$o);
	}

	/**
	 * Site setup
	 *
	 * @note This method is protected by the routes
	 * @param Request $request
	 * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
	 */
	public function setup(Request $request)
	{
		if ($request->post()) {
			$validated = $request->validate([
				'site_name' => 'required|string|min:2|max:255',
				'site_email' => 'required|string|email|max:255',
				'site_address1' => 'required|string|min:2|max:255',
				'site_address2' => 'nullable|string|min:2|max:255',
				'site_city' => 'required|string|min:2|max:64',
				'site_state' => 'required|string|min:2|max:32',
				'site_postcode' => 'required|string|min:2|max:8',
				'site_description' => 'nullable|string|min:5',
				'site_phone' => 'nullable|regex:/[0-9 ]+/|min:6|max:12',
				'site_fax' => 'nullable|regex:/[0-9 ]+/|min:6|max:12',
				'site_tax' => 'required|regex:/[0-9 ]+/|size:14',
				'social' => 'nullable|array',
				'top_menu' => 'nullable|array',
				'site_logo' => 'nullable|image',
				'email_logo' => 'nullable|image',
			]);

			$site = config('site');

			// @todo - not currently rendered in the home page
			$validated['social'] = [];
			$validated['top_menu'] = [];

			// Handle the images
			foreach(['site_logo','email_logo'] as $key)
				if (array_key_exists($key,$validated))
					$validated[$key] = ($x=$validated[$key])->storeAs('site/'.$site->site_id,$x->getClientOriginalName(),'public');

			foreach ($site->details as $oo)
				if (array_key_exists($oo->key,$validated)) {
					$oo->value = Arr::get($validated,$oo->key);
					$oo->save();

					unset($validated[$oo->key]);
				}

			// Left over values to be created.
			foreach ($validated as $k=>$v) {
				$oo = new SiteDetail;
				$oo->key = $k;
				$oo->value = $v ?: '';

				$site->details()->save($oo);
			}

			return redirect()->back()
				->with('success','Settings saved');
		}

		return view('a.setup');
	}
}