<?php

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

use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Config;
use Carbon\Carbon;
use App\Modules\Bookings\Message;
use App\Modules\Clients\Client;
use App\Modules\Clients\Customer;
use App\Modules\Clients\Site;
use App\Modules\Clients\SiteUser;
use App\Http\Controllers\BaseController;
use Illuminate\Http\Request;

class MarketingControllerREST extends BaseController
{
    /**
     * Determines how many customers can be reached based
     * on the filters passed.
     *
     * @return int
     */
    public function getReach(Request $request)
    {
        $total = 0;

        // First of all retrieve all customers
        // only when there isn't a client type or
        // the client_type contains customers
        $customers = $this->getCustomersQuery($request->all());

        if ($customers !== false) {
            // Get totals
            $total += $customers->count();
        }

        // Next move onto the business customers
        // again we will only retrieve it when the filter is not active
        // or the filter contains business customers
        $clients = $this->getClientsQuery($request->all());

        if ($clients !== false) {
            // Get totals
            $total += $clients->count();
        }

        return [
            'total' => $total,
        ];
    }

    /**
     * Sends the email out to the pre-filtered customers.
     *
     * @return \Illuminate\Http\Response
     */
    public function postSend(Request $request)
    {
        // Fake the email send
        Mail::pretend();

        // First we are sending to all the clients
        // but before so we are checking to make sure that the
        // customers are selected in the multi select box
        $query = $this->getCustomersQuery($request->all());

        if ($query !== false) {
            // The $query variable is a query that is not fired yet, so we do that now
            $customers = $query->get();

            foreach ($customers as $customer) {
                Mail::queue('emails.dbtemplate', ['template' => $request->input('message')], function ($message) use ($customer, $request) {
                    $message->to($customer->email)->subject($request->input('subject'));
                });
            }
        }

        // We are checking to see if the client_type array contains 'client'
        // and if so we are fetching a list of clients that are matching
        // the selected filters and fire off the emails
        $query = $this->getClientsQuery($request->all());
        if ($query !== false) {
            // Fire the query...
            $clients = $query->get();

            foreach ($clients as $client) {
                // We need to determine the email address
                // and to do so we will first get a list of sites that have users
                $site_user = SiteUser::whereNotNull('email')->whereHas('site', function ($q) use ($client) {
                    $q->where('sites.client_id', $client->id);
                })->first();

                Mail::queue('emails.dbtemplate', ['template' => $request->input('message')], function ($message) use ($client, $site_user, $request) {
                    $message->to($site_user->email)->subject($request->input('subject'));
                });
            }
        }
    }

    /**
     * Sends a preview email to the logged in user.
     *
     * @return \Illuminate\Http\Response
     */
    public function postPreview(Request $request)
    {
        // Skip if the user doesn't have an email
        // or the email address is invalid
        // in certain cases people have email addresses like '1'
        // and we need to ignore those
        if (! Auth::user()->email || ! filter_var(Auth::user()->email, FILTER_VALIDATE_EMAIL)) {
            return Response::json(['error' => 'Your email is invalid. Please set your email address from the Settings menu.'], 400);
        }

        // Fake the email send
        Mail::pretend();

        Mail::send('emails.dbtemplate', ['template' => $request->input('message')], function ($message) use ($request) {
            $message->to(Auth::user()->email)->subject($request->input('subject'));
        });

        return ['message' => 'A preview email was sent to '.Auth::user()->email];
    }

    /**
     * Downloads an existing CSV file.
     *
     * @param  string $filename
     *
     * @return \Illuminate\Http\Response
     */
    public function getExport($filename)
    {
        // If we have a filename then we will try to serve that file
        if ($filename) {
            return Response::download(Config::get('files.path').'/'.$filename, 'Marketing '.date('d-m-Y').'.csv');
        }

        throw new Exception('File was not found');
    }

    /**
     * Exports the curently targeted customers to a CSV.
     *
     * @return \Illuminate\Http\Response
     */
    public function postExport(Request $request)
    {
        // Open a new CSV file to write to
        // the file has to have a unique name
        $filename = str_random(32).'.csv';
        $saveTo = Config::get('files.path').'/'.$filename;
        $fp = fopen($saveTo, 'w');

        if (! $fp) {
            return Response::json(['error' => 'Unable to write to a new file'], 400);
        }

        // Set the file headers
        fputcsv($fp, ['First Name', 'Last Name', 'Company Name', 'Email', 'Phone Number']);

        // Fetch the SQL query for customers
        $query = $this->getCustomersQuery($request->all());

        if ($query !== false) {
            $customers = $query->get();

            foreach ($customers as $customer) {
                fputcsv($fp, [
                    'first_name' => $customer->first_name,
                    'last_name'  => $customer->last_name,
                    'business'   => '',
                    'email'      => $customer->email,
                    'phone'      => $customer->phone,
                ]);
            }
        }

        // Next we will do the same thing with business customers
        $query = $this->getClientsQuery($request->all());
        if ($query !== false) {
            $clients = $query->get();

            foreach ($clients as $client) {
                // We need to determine the email address
                // and to do so we will first get a list of sites that have users
                $site_user = SiteUser::whereNotNull('email')->whereHas('site', function ($q) use ($client) {
                    $q->where('sites.client_id', $client->id);
                })->first();

                fputcsv($fp, [
                    'fist_name' => $site_user->first_name,
                    'last_name' => $site_user->last_name,
                    'business'  => $client->name,
                    'email'     => $site_user->email,
                    'phone'     => $site_user->phone,
                ]);
            }
        }

        fclose($fp);

        return ['filename' => $filename];
    }

    /**
     * Applies custom filters on a given query.
     *
     * @param  \Illuminate\Database\Eloquent\Builder $query
     * @param  array 								 $filters
     * @param  string 								 $type
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    protected function applyFilters(&$query, $filters, $type = 'client')
    {
        // Before we apply the filters we need to check
        // if there are any fields that contain [] in the array key
        // this happens when the request doesn't come through GET
        foreach ($filters as $key => $value) {
            if (strpos($key, '[]') !== false) {
                $filters[str_replace('[]', '', $key)] = $value;
                unset($filters[$key]);
            }
        }

        if (isset($filters['task_type']) && ! empty($filters['task_type']) && is_array($filters['task_type'])) {
            $query->whereHas('tasks', function ($q) use ($filters) {
                $q->whereIn('tasks.type', $filters['task_type']);
            });
        }

        if (isset($filters['inactive_since']) && ! empty($filters['inactive_since'])) {
            $query->whereHas('tasks', function ($q) use ($filters) {
                $q->where('tasks.created_at', '>', Carbon::parse($filters['inactive_since'])->toDateTimeString());
            }, '=', 0);
        }

        if (isset($filters['tasks_operator']) && ! empty($filters['tasks_operator'])) {
            // Check to see if the value has been entered
            if (isset($filters['tasks_count']) && ! empty($filters['tasks_count'])) {
                // Here we are testing to see if the customer
                // has more or less tasks booked in
                $query->has('tasks', $filters['tasks_operator'], $filters['tasks_count']);
            }
        }

        if (isset($filters['has_email']) && ! empty($filters['has_email'])) {
            if ($type == 'client') {
                $query->whereHas('sites', function ($q) {
                    $q->whereHas('users', function ($q2) {
                        $q2->whereNotNull('email');
                    });
                });
            } else {
                $query->where('email', '!=', '');
            }
        }

        if (isset($filters['spent_operator']) && ! empty($filters['spent_operator'])) {
            // Check to see if the value has been entered
            if (isset($filters['spent']) && ! empty($filters['spent'])) {
                // Here we are testing to see if the customer
                // has spent more or less that the specified value in labour
                $query->whereHas('tasks', function ($q) use ($filters) {
                    $q->select(DB::raw('sum(labour)'));
                }, $filters['spent_operator'], $filters['spent']);
            }
        }

        return $query;
    }

    /**
     * Returns a list of customers that match our filters.
     *
     * @param array $filters
     *
     * @return \Illuminate\Database\Eloquent\Builder or FALSE
     */
    protected function getCustomersQuery($filters)
    {
        $filters['client_type'] = $this->getClientType($filters);

        // Checking to see if the array is empty (no filter on client_type)
        // or if it has the element 'customer' then we will proceed
        if (empty($filters['client_type']) || array_search('customer', $filters['client_type']) !== false) {
            $customers = Customer::query();

            return $this->applyFilters($customers, $filters, 'customer');
        }

        return false;
    }

    /**
     * Returns a list of clients that match our filters.
     *
     * @param array $filters
     *
     * @return \Illuminate\Database\Eloquent\Builder or FALSE
     */
    protected function getClientsQuery($filters)
    {
        $filters['client_type'] = $this->getClientType($filters);

        // Checking to see if the array is empty (no filter on client_type)
        // or if it has the element 'client' then we will proceed
        if (empty($filters['client_type']) || array_search('client', $filters['client_type']) !== false) {
            $clients = Client::query();

            return $this->applyFilters($clients, $filters, 'client');
        }

        return false;
    }

    /**
     * Check to see if the client_type is set and if it is an array
     * otherwise initialize as an empty array. This function makes sure
     * that the result is always an array either empty or with values.
     *
     * @param array $filters
     *
     * @return array
     */
    protected function getClientType($filters)
    {
        // WHen the request comes through a POST
        // the square brackets are added to the client type automatically
        // so we need to remove them
        if (isset($filters['client_type[]'])) {
            $filters['client_type'] = $filters['client_type[]'];
        }

        if (! isset($filters['client_type']) || ! is_array($filters['client_type'])) {
            $filters['client_type'] = [];
        }

        return $filters['client_type'];
    }
}
