<?php

namespace App\Modules\Clients\controllers\api\v1;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Exception;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Log;
use App\Modules\Bookings\Task;
use App\Http\Controllers\BaseController;
use Illuminate\Http\Request as BaseRequest;
use App\Modules\Clients\Client;
use App\Modules\Clients\Site;
use App\Modules\Clients\SiteUser;

class ClientsControllerREST extends BaseController
{
    /**
     * Return all the records as an encoded JSON.
     *
     * @return JSON
     */
    public function all()
    {

        // Get an instance of a client so we can retrieve the table name
        $client = new Client();

        $data = DB::table($client->getTable())->whereNull('deleted_at')->orderBy('id', 'desc')->get();
        $total = count($data);

        $response = [
            'success'      => true,
            'data'         => $data,
            'total'        => $total,
            'current_page' => 1,
            'last_page'    => 1,
            'from'         => 1,
            'to'           => $total,
        ];

        return $response;
    }

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index(BaseRequest $request)
    {
        // Check to see if all the records were requested
        if ($request->get('all') && $request->get('all') != 'false') {
            return $this->all();
        }

        $query = Client::query()->select('*');

        if ($request->get('q')) {
            $query->select('clients.*')
                ->join('sites', 'sites.client_id', '=', 'clients.id')
                ->join('site_users', 'site_users.site_id', '=', 'sites.id')
                ->groupBy('clients.id');

            $query = $query->where(function ($query) use ($request) {
                    return $query->where('clients.name', 'like', '%'.$request->get('q').'%')
                        ->orWhere('sites.primary_phone', 'like', $request->get('q').'%')
                        ->orWhere('site_users.phone', 'like', $request->get('q').'%')
                        ->orWhere('site_users.mobile', 'like', $request->get('q').'%');
                });
        }
        if ($request->get('name') && $request->get('equal', false)) {
            $query = $query->where('name', $request->get('name'));
        } elseif ($request->get('name')) {
            $query = $query->where('name', 'like', '%'.$request->get('name').'%');
        }

        $with = [];
        if ($request->get('items')) {
            $with[] = 'items';
        }

        if ($request->get('sites')) {
            $with[] = 'sites';
        }

        if ($request->get('site_users')) {
            $with[] = 'sites.users';
        }

        if ($request->get('primary_site')) {
            $with[] = 'primary_site';
        }

        if ($request->get('primary_contact')) {
            $with[] = 'primary_contact';
        }

        if ($request->get('sla')) {
            $with[] = 'sla';
        }

        if ($request->get('contract')) {
            $with[] = 'contract';
        }
        $query->with($with);

        if ($request->get('client_id')) {
            $query = $query->where('client_id', $request->get('client_id'));
        }

        if ($request->get('modifiedSince')) {
            $query->where('clients.updated_at', '>=', $request->get('modifiedSince'));
        }

        $query->orderBy('clients.id', 'desc');

        // Apply limits and execute the query
        // $query = $query->take($request->get('limit', 20))->skip($request->get('skip', 0))->get();
        $query = $query->paginate($request->get('limit', 20));

        if ($request->get('active_tasks')) {
            foreach ($query as $value) {
                $value->active_tasks = Task::query()->open()->where('client_id', $value->id)->where('client_type', 'client')->count();

                if ($request->get('revenue')) {
                    $value->revenue = Task::query()->where('client_id', $value->id)->where('client_type', 'client')->sum('labour');
                }
            }
        }

        $response = [
            'success'      => true,
            'data'         => $query->getCollection()->toArray(),
            'total'        => $query->total(),
            'current_page' => $query->currentPage(),
            'last_page'    => $query->lastPage(),
            'from'         => $query->firstItem(),
            'to'           => $query->lastItem(),
        ];

        return Response::json($response);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store(\App\Http\Requests\StoreClientRequest $request)
    {
        $client = new Client();
        Log::info('Client store called with following data:');
        Log::info($request->all());

        try {
            DB::transaction(function () use (&$client, $request) {
                $client->fill($request->all());
                $client->save();

                // Save all the sites
                foreach ($request->get('sites', []) as $SiteData) {
                    $site = new Site($SiteData);
                    $site = $client->sites()->save($site);

                    // Save all the site users
                    if (isset($SiteData['users']) && is_array($SiteData['users'])) {
                        foreach ($SiteData['users'] as $UserData) {
                            $user = new SiteUser($UserData);
                            $user->site_id = $site->id;
                            $user = $site->users()->save($user);
                        }
                    }
                }

                $client->load('sites.users');

                event('ClientCreated', $client);
            });

            return $client;
        } catch (\Illuminate\Database\UniqueConstraintViolationException $e) {
            return Response::json([
                'error' => 'A business with this name already exists. Please choose a different name.'
            ], 422);
        } catch (\Exception $e) {
            Log::error('Error creating client: ' . $e->getMessage());
            return Response::json([
                'error' => 'An error occurred while creating the business. Please try again.'
            ], 500);
        }
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function show(BaseRequest $request, $id)
    {
        $client = Client::query()->find($id);

        if (!$client) {
            return Response::json(['error' => 'Client not found'], 404);
        }

        $with = ['ContractsTask','sites', 'primary_site', 'primary_contact', 'sla'];

        $client->monthly_allowance_left = $client->monthlyAllowanceLeft();
        $client->EmergencyUsed = $client->EmergencyUsed();
        $client->EmergencyRemaining = ($client->emergency ?? 0) - $client->EmergencyUsed();
        $client->RecurringUsed = $client->RecurringUsed();
        $client->RecurringRemaining = ($client->recurring ?? 0) - $client->RecurringUsed();
        $client->subscribed = $client->subscribers()->where('id', Auth::id())->count() ? true : false;

        if ($request->get('site_users')) {
            $with[] = 'sites.users';
        }
        $client->load($with);

        $response = [
            'success' => true,
            'data'    => $client->toArray(),
        ];

        return Response::json($response);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Subscribe the currently logged in user to the specified client.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function subscribe($id)
    {
        $client = Client::query()->find($id);

        if (!$client) {
            return Response::json(['error' => 'Client not found'], 404);
        }

        Auth::user()->subscriptions()->attach($client);

        $response = [
            'success' => true,
            'message' => 'Subscribed to client ' . $client->name,
        ];

        return Response::json($response);
    }

    /**
     * Unsubscribe the currently logged in user from the specified client.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function unsubscribe($id)
    {
        $client = Client::query()->find($id);

        if (!$client) {
            return Response::json(['error' => 'Client not found'], 404);
        }

        Auth::user()->subscriptions()->detach($client);

        $response = [
            'success' => true,
            'message' => 'Unsubscribed from client ' . $client->name,
        ];

        return Response::json($response);
    }

    /**
     * Get list of client subscriptions for the currently logged in user.
     *
     * @return Response
     */
    public function getSubscriptions()
    {
        $subscriptions = Auth::user()->subscriptions();

        $response = [
            'success' => true,
            'data'    => $subscriptions->get()->toArray(),
        ];

        return Response::json($response);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function update(BaseRequest $request, $id)
    {
        $client = Client::query()->find($id);

        if (! $client) {
            return Response::json(['error' => 'Client not found'], 404);
        }

        $client->fill($request->all());

        if ($client->save()) {
            event('ClientUpdated', $client);

            $response = ['success' => true, 'data' => $client->toArray()];
        } else {
            $response = ['success' => false, 'error' => $client->errors];
        }

        return Response::json($response);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function destroy($id)
    {
        if (Gate::denies('delete-client')) {
            abort(403);
        }

        $client = Client::query()->find($id);

        // Access validations
        // should be implemented here...

        if (! $client) {
            return Response::json(['error' => 'Client not found'], 404);
        }

        if ($client->delete()) {
            return Response::json($client->toArray());
        } else {
            return Response::json(['errors' => $client->errors->all()], 400);
        }
    }
}
