<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

use App\Classes\File;
use App\Classes\FTN\Packet;
use App\Http\Requests\SetupRequest;
use App\Models\File as FileModel;
use App\Models\{Address,Domain,Echomail,Netmail,Setup,System};

class HomeController extends Controller
{
	public function home()
	{
		return redirect(Auth::check() ? 'dashboard' : 'about');
	}

	public function file_contents(System $o,string $date)
	{
		$f = FileModel::select('files.*')
			->distinct()
			->leftJoin('file_seenby',['file_seenby.file_id'=>'files.id'])
			->where(function($query) use ($o,$date) {
				return $query
					->where('created_at',$date)
					->whereIn('fftn_id',$o->addresses->pluck('id'));
			})
			->Orwhere(function($query) use ($o,$date) {
				return $query
					->where('sent_at',$date)
					->whereIn('address_id',$o->addresses->pluck('id'));
			})
			->get();

		return view('file')
			->with('f',$f);
	}

	public function network(Domain $o)
	{
		if (! $o->public && ! Gate::check('admin',$o))
			abort(404);

		$o->load(['zones.system','zones.domain']);

		return view('domain.view')
			->with('o',$o);
	}

	public function packet_contents(System $o,string $packet)
	{
		$nm = Netmail::select('netmails.*')
			->distinct()
			->leftJoin('netmail_path',['netmail_path.netmail_id'=>'netmails.id'])
			->where(function($query) use ($o,$packet) {
				return $query
					->where('sent_pkt',$packet)
					->orWhere('netmail_path.recv_pkt',$packet);
			})
			->get();

		$em = Echomail::select('echomails.*')
			->distinct()
			->leftJoin('echomail_seenby',['echomail_seenby.echomail_id'=>'echomails.id'])
			->leftJoin('echomail_path',['echomail_path.echomail_id'=>'echomails.id'])
			->where(function($query) use ($o,$packet) {
				return $query
					->where('sent_pkt',$packet)
					->whereIn('echomail_seenby.address_id',$o->addresses->pluck('id'));
			})
			->orWhere(function($query) use ($o,$packet) {
				return $query
					->where('recv_pkt',$packet)
					->whereIn('echomail_path.address_id',$o->addresses->pluck('id'));
			})
			->with('echoarea')
			->get();

		return view('packet')
			->with('nm',$nm)
			->with('em',$em);
	}

	/**
	 * Render a view that summarises the users permissions
	 */
	public function permissions()
	{
		return view('auth.permissions')
			->with('user',Auth::user());
	}

	/**
	 * Show a packet dump
	 *
	 * @param Request $request
	 * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
	 */
	public function pkt(Request $request)
	{
		$pkt = collect();
		$file = NULL;
		$f = NULL;

		if ($request->post()) {
			$request->validate([
				'file' => 'required|filled|min:1',
			]);

			foreach ($request->allFiles() as $key => $filegroup) {
				if ($key !== 'file')
					continue;

				foreach ($filegroup as $file) {
					try {
						$f = new File($file);

						foreach ($f as $packet)
							$pkt->push([$f->itemName()=>Packet::process($packet,$f->itemName(),$f->itemSize())]);

					} catch (\Exception $e) {
						return redirect()->back()->withErrors(sprintf('%s (%s:%d)',$e->getMessage(),$e->getFile(),$e->getLine()));
					}

					break;
				}
			}
		}

		return view('pkt')
			->with('file',$f)
			->with('filename',$f ? $file->getClientOriginalName() : NULL)
			->with('results',$pkt)
			->with('hexdump',$file ? hex_dump(file_get_contents($file)) : '');
	}

	/**
	 * Process searching
	 *
	 * @param Request $request
	 * @return Collection
	 */
	public function search(Request $request): Collection
	{
		$this->middleware('auth');

		$result = collect();

		list($zone_id,$host_id,$node_id,$point_id,$domain) = sscanf($request->query('term'),'%d:%d/%d.%d@%s');

		// Look for Systems
		foreach (Address::select(['systems.name',DB::raw('systems.id AS system_id'),'zones.zone_id','region_id','host_id','node_id','point_id'])
			->join('zones',['zones.id'=>'addresses.zone_id'])
			->rightjoin('systems',['systems.id'=>'addresses.system_id'])
			->when($zone_id || $host_id || $node_id,function($query) use ($zone_id,$host_id,$node_id) {
				return $query
					->when($zone_id,function($q,$zone_id) { return $q->where('zones.zone_id',$zone_id); })
					->where(function($q) use ($host_id) {
						return $q
							->when($host_id,function($q,$host_id) { return $q->where('region_id',$host_id); })
							->when($host_id,function($q,$host_id) { return $q->orWhere('host_id',$host_id); });
					})
					->when($node_id,function($q,$node_id) { return $q->where('node_id',$node_id); });
			})
			->orWhere('systems.name','ilike','%'.$request->query('term').'%')
			->orWhere('systems.sysop','ilike','%'.$request->query('term').'%')
			->OrderBy('systems.name')
			->get() as $o)
		{
			$ftn = NULL;

			if ($o->zone_id && ($o->region_id||$o->host_id) && is_numeric($o->node_id) && is_numeric($o->point_id))
				$ftn = sprintf('%d:%d/%d.%d',$o->zone_id,$o->host_id ?: $o->region_id,$o->node_id,$o->point_id);

			$result->push(['id'=>$o->system_id,'name'=>htmlspecialchars($o->name).($ftn ? ' '.$ftn : ''),'value'=>url('system/view',[$o->system_id]),'category'=>'Systems']);
		}

		// Look for Echomail
		foreach (Echomail::select(['id','fftn_id','from'])
				->where('msgid','like','%'.$request->query('term').'%')
				->orWhere('replyid','like','%'.$request->query('term').'%')
				->get() as $o)
		{
			$result->push(['id'=>$o->id,'name'=>sprintf('%s (%s)',$o->from,$o->fftn->ftn3d),'value'=>url('echomail/view',[$o->id]),'category'=>'Echomail']);
		}

		// Look for Netmail
		if (Gate::check('admin'))
			foreach (Netmail::select(['id','fftn_id','from'])
						 ->where('msgid','like','%'.$request->query('term').'%')
						 ->orWhere('replyid','like','%'.$request->query('term').'%')
						 ->get() as $o)
			{
				$result->push(['id'=>$o->id,'name'=>sprintf('%s (%s)',$o->from,$o->fftn->ftn3d),'value'=>url('netmail/view',[$o->id]),'category'=>'Netmail']);
			}

		return $result->unique(['id'])->take(10)->values();
	}

	/**
	 * System Setup
	 *
	 * @note: Protected by Route
	 */
	public function setup(SetupRequest $request)
	{
		$o = Setup::findOrNew(config('app.id'));

		if ($request->post()) {
			if (! $o->exists)
				$o->id = config('app.id');

			$servers = collect();
			$options = collect();

			$x = collect();
			$x->put('options',collect($request->post('binkp'))->sum());
			$x->put('port',$request->post('binkp_port'));
			$x->put('bind',$request->post('binkp_bind'));
			$x->put('active',(bool)$request->post('binkp_active'));
			$servers->put('binkp',$x);

			$x = collect();
			$x->put('options',collect($request->post('emsi'))->sum());
			$x->put('port',$request->post('emsi_port'));
			$x->put('bind',$request->post('emsi_bind'));
			$x->put('active',(bool)$request->post('emsi_active'));
			$servers->put('emsi',$x);

			$x = collect();
			$x->put('options',collect($request->post('dns'))->sum());
			$x->put('port',$request->post('dns_port'));
			$x->put('bind',$request->post('dns_bind'));
			$x->put('active',(bool)$request->post('dns_active'));
			$servers->put('dns',$x);

			$options->put('options',collect($request->post('options'))->sum());
			$options->put('msgs_pkt',$request->post('msgs_pkt'));

			$o->servers = $servers;
			$o->options = $options;
			$o->system_id = $request->post('system_id');
			$o->save();
		}

		return view('setup')
			->with('o',$o);
	}
}