<?php

namespace App\Http\Controllers;

use App\Events\SubdomainWasRemoved;
use App\Events\SubdomainWasUpdated;
use App\Events\UserSettingsChanged;
use App\Events\UserSignedUp;
use App\Http\Requests\SaveClientPortalSettings;
use App\Http\Requests\SaveEmailSettings;
use App\Http\Requests\UpdateAccountRequest;
use App\Models\Account;
use App\Models\AccountGateway;
use App\Models\Affiliate;
use App\Models\Document;
use App\Models\Gateway;
use App\Models\GatewayType;
use App\Models\Invoice;
use App\Models\InvoiceDesign;
use App\Models\License;
use App\Models\PaymentTerm;
use App\Models\Product;
use App\Models\TaxRate;
use App\Models\User;
use App\Models\AccountEmailSettings;
use App\Ninja\Mailers\ContactMailer;
use App\Ninja\Mailers\UserMailer;
use App\Ninja\Repositories\AccountRepository;
use App\Ninja\Repositories\ReferralRepository;
use App\Services\AuthService;
use App\Services\PaymentService;
use App\Services\TemplateService;
use Nwidart\Modules\Facades\Module;
use Auth;
use Cache;
use File;
use Image;
use Input;
use Redirect;
use Request;
use Response;
use Session;
use stdClass;
use Exception;
use URL;
use Utils;

use Validator;
use View;
use App\Jobs\PurgeClientData;

/**
 * Class AccountController.
 */
class AccountController extends BaseController
{
    /**
     * @var AccountRepository
     */
    protected $accountRepo;

    /**
     * @var UserMailer
     */
    protected $userMailer;

    /**
     * @var ContactMailer
     */
    protected $contactMailer;

    /**
     * @var ReferralRepository
     */
    protected $referralRepository;

    /**
     * @var PaymentService
     */
    protected $paymentService;

    /**
     * AccountController constructor.
     *
     * @param AccountRepository  $accountRepo
     * @param UserMailer         $userMailer
     * @param ContactMailer      $contactMailer
     * @param ReferralRepository $referralRepository
     * @param PaymentService     $paymentService
     */
    public function __construct(
        AccountRepository $accountRepo,
        UserMailer $userMailer,
        ContactMailer $contactMailer,
        ReferralRepository $referralRepository,
        PaymentService $paymentService
    ) {
        $this->accountRepo = $accountRepo;
        $this->userMailer = $userMailer;
        $this->contactMailer = $contactMailer;
        $this->referralRepository = $referralRepository;
        $this->paymentService = $paymentService;
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    public function getStarted()
    {
        $user = false;
        $account = false;
        $guestKey = Input::get('guest_key'); // local storage key to login until registered

        if (Auth::check()) {
            return Redirect::to('invoices/create');
        }

        if (! Utils::isNinja() && Account::count() > 0) {
            return Redirect::to('/login');
        }

        if ($guestKey) {
            $user = User::where('password', '=', $guestKey)->first();

            if ($user && $user->registered) {
                return Redirect::to('/');
            }
        }

        if (! $user) {
            $account = $this->accountRepo->create();
            $user = $account->users()->first();
        }

        Auth::login($user, true);
        event(new UserSignedUp());

        if ($account && $account->language_id && $account->language_id != DEFAULT_LANGUAGE) {
            $link = link_to('/invoices/create?lang=en', 'click here');
            $message = sprintf('Your account language has been set automatically, %s to change to English', $link);
            Session::flash('warning', $message);
        }

        if ($redirectTo = Input::get('redirect_to')) {
            $redirectTo = SITE_URL . '/' . ltrim($redirectTo, '/');
        } else {
            $redirectTo = Input::get('sign_up') ? 'dashboard' : 'invoices/create';
        }

        return Redirect::to($redirectTo)->with('sign_up', Input::get('sign_up'));
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    public function changePlan()
    {
        $user = Auth::user();
        $account = $user->account;
        $company = $account->company;

        $plan = Input::get('plan');
        $term = Input::get('plan_term');
        $numUsers = Input::get('num_users');

        if ($plan != PLAN_ENTERPRISE) {
            $numUsers = 1;
        }

        $planDetails = $account->getPlanDetails(false, false);

        $newPlan = [
            'plan' => $plan,
            'term' => $term,
            'num_users' => $numUsers,
        ];
        $newPlan['price'] = Utils::getPlanPrice($newPlan);
        $credit = 0;

        if ($plan == PLAN_FREE && $company->processRefund(Auth::user())) {
            Session::flash('warning', trans('texts.plan_refunded'));
        }

        if ($company->payment && ! empty($planDetails['paid']) && $plan != PLAN_FREE) {
            $time_used = $planDetails['paid']->diff(date_create());
            $days_used = $time_used->days;

            if ($time_used->invert) {
                // They paid in advance
                $days_used *= -1;
            }

            $days_total = $planDetails['paid']->diff($planDetails['expires'])->days;
            $percent_used = $days_used / $days_total;
            $credit = round(floatval($company->payment->amount) * (1 - $percent_used), 2);
        }

        if ($newPlan['price'] > $credit) {
            $invitation = $this->accountRepo->enablePlan($newPlan, $credit);
            return Redirect::to('view/' . $invitation->invitation_key);
        } else {
            if ($plan == PLAN_FREE) {
                $company->discount = 0;

                $ninjaClient = $this->accountRepo->getNinjaClient($account);
                $ninjaClient->send_reminders = false;
                $ninjaClient->save();
            } else {
                $company->plan_term = $term;
                $company->plan_price = $newPlan['price'];
                $company->num_users = $numUsers;
                $company->plan_expires = date_create()->modify($term == PLAN_TERM_MONTHLY ? '+1 month' : '+1 year')->format('Y-m-d');
            }

            $company->trial_plan = null;
            $company->plan = $plan;
            $company->save();

            Session::flash('message', trans('texts.updated_plan'));

            return Redirect::to('settings/account_management');
        }
    }

    /**
     * @param $entityType
     * @param $visible
     * @param mixed $filter
     *
     * @return mixed
     */
    public function setEntityFilter($entityType, $filter = '')
    {
        if ($filter == 'true') {
            $filter = '';
        }

        // separate state and status filters
        $filters = explode(',', $filter);
        $stateFilter = [];
        $statusFilter = [];
        foreach ($filters as $filter) {
            if (in_array($filter, \App\Models\EntityModel::$statuses)) {
                $stateFilter[] = $filter;
            } else {
                $statusFilter[] = $filter;
            }
        }

        Session::put("entity_state_filter:{$entityType}", implode(',', $stateFilter));
        Session::put("entity_status_filter:{$entityType}", implode(',', $statusFilter));

        return RESULT_SUCCESS;
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function getSearchData()
    {
        $data = $this->accountRepo->getSearchData(Auth::user());

        return Response::json($data);
    }

    /**
     * @param bool $section
     *
     * @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
     */
    public function showSection($section = false)
    {
        if (! Auth::user()->is_admin) {
            return Redirect::to('/settings/user_details');
        }

        if (! $section) {
            return Redirect::to('/settings/'.ACCOUNT_COMPANY_DETAILS, 301);
        }

        if ($section == ACCOUNT_COMPANY_DETAILS) {
            return self::showCompanyDetails();
        } elseif ($section == ACCOUNT_LOCALIZATION) {
            return self::showLocalization();
        } elseif ($section == ACCOUNT_PAYMENTS) {
            return self::showOnlinePayments();
        } elseif ($section == ACCOUNT_BANKS) {
            return self::showBankAccounts();
        } elseif ($section == ACCOUNT_INVOICE_SETTINGS) {
            return self::showInvoiceSettings();
        } elseif ($section == ACCOUNT_IMPORT_EXPORT) {
            return View::make('accounts.import_export', ['title' => trans('texts.import_export')]);
        } elseif ($section == ACCOUNT_MANAGEMENT) {
            return self::showAccountManagement();
        } elseif ($section == ACCOUNT_INVOICE_DESIGN || $section == ACCOUNT_CUSTOMIZE_DESIGN) {
            return self::showInvoiceDesign($section);
        } elseif ($section == ACCOUNT_CLIENT_PORTAL) {
            return self::showClientPortal();
        } elseif ($section === ACCOUNT_TEMPLATES_AND_REMINDERS) {
            return self::showTemplates();
        } elseif ($section === ACCOUNT_PRODUCTS) {
            return self::showProducts();
        } elseif ($section === ACCOUNT_TAX_RATES) {
            return self::showTaxRates();
        } elseif ($section === ACCOUNT_PAYMENT_TERMS) {
            return self::showPaymentTerms();
        } elseif ($section === ACCOUNT_SYSTEM_SETTINGS) {
            return self::showSystemSettings();
        } else {
            $view = "accounts.{$section}";
            if (! view()->exists($view)) {
                return redirect('/settings/company_details');
            }

            $data = [
                'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
                'title' => trans("texts.{$section}"),
                'section' => $section,
            ];

            return View::make($view, $data);
        }
    }

    /**
     * @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
     */
    private function showSystemSettings()
    {
        if (Utils::isNinjaProd()) {
            return Redirect::to('/');
        }

        $data = [
            'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
            'title' => trans('texts.system_settings'),
            'section' => ACCOUNT_SYSTEM_SETTINGS,
        ];

        return View::make('accounts.system_settings', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showInvoiceSettings()
    {
        $account = Auth::user()->account;
        $recurringHours = [];

        for ($i = 0; $i < 24; $i++) {
            if ($account->military_time) {
                $format = 'H:i';
            } else {
                $format = 'g:i a';
            }
            $recurringHours[$i] = date($format, strtotime("{$i}:00"));
        }

        $data = [
            'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
            'title' => trans('texts.invoice_settings'),
            'section' => ACCOUNT_INVOICE_SETTINGS,
            'recurringHours' => $recurringHours,
        ];

        return View::make('accounts.invoice_settings', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showCompanyDetails()
    {
        // check that logo is less than the max file size
        $account = Auth::user()->account;
        if ($account->isLogoTooLarge()) {
            Session::flash('warning', trans('texts.logo_too_large', ['size' => $account->getLogoSize().'KB']));
        }

        $data = [
            'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
            'sizes' => Cache::get('sizes'),
            'title' => trans('texts.company_details'),
        ];

        return View::make('accounts.details', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showAccountManagement()
    {
        $account = Auth::user()->account;
        $planDetails = $account->getPlanDetails(true, false);
        $portalLink = false;

        if (Utils::isNinja() && $planDetails
            && $account->getPrimaryAccount()->id == auth()->user()->account_id
            && $ninjaClient = $this->accountRepo->getNinjaClient($account)) {
            $contact = $ninjaClient->getPrimaryContact();
            $portalLink = $contact->link;
        }

        $data = [
            'account' => $account,
            'portalLink' => $portalLink,
            'planDetails' => $planDetails,
            'title' => trans('texts.account_management'),
        ];

        return View::make('accounts.management', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    public function showUserDetails()
    {
        if (! auth()->user()->registered) {
            return redirect('/')->withError(trans('texts.sign_up_to_save'));
        }

        $oauthLoginUrls = [];
        foreach (AuthService::$providers as $provider) {
            $oauthLoginUrls[] = ['label' => $provider, 'url' => URL::to('/auth/'.strtolower($provider))];
        }

        $data = [
            'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
            'title' => trans('texts.user_details'),
            'user' => Auth::user(),
            'oauthProviderName' => AuthService::getProviderName(Auth::user()->oauth_provider_id),
            'oauthLoginUrls' => $oauthLoginUrls,
            'referralCounts' => $this->referralRepository->getCounts(Auth::user()->referral_code),
        ];

        return View::make('accounts.user_details', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showLocalization()
    {
        $data = [
            'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
            'timezones' => Cache::get('timezones'),
            'dateFormats' => Cache::get('dateFormats'),
            'datetimeFormats' => Cache::get('datetimeFormats'),
            'title' => trans('texts.localization'),
            'weekdays' => Utils::getTranslatedWeekdayNames(),
            'months' => Utils::getMonthOptions(),
        ];

        return View::make('accounts.localization', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showBankAccounts()
    {
        $account = auth()->user()->account;

        return View::make('accounts.banks', [
            'title' => trans('texts.bank_accounts'),
            'advanced' => ! Auth::user()->hasFeature(FEATURE_EXPENSES),
            'warnPaymentGateway' => ! $account->account_gateways->count(),
        ]);
    }

    /**
     * @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
     */
    private function showOnlinePayments()
    {
        $account = Auth::user()->account;
        $account->load('account_gateways');
        $count = $account->account_gateways->count();
        $trashedCount = AccountGateway::scope()->withTrashed()->count();

        if ($accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE)) {
            if (! $accountGateway->getPublishableKey()) {
                Session::now('warning', trans('texts.missing_publishable_key'));
            }
        }

        $tokenBillingOptions = [];
        for ($i = 1; $i <= 4; $i++) {
            $tokenBillingOptions[$i] = trans("texts.token_billing_{$i}");
        }

        return View::make('accounts.payments', [
            'showAdd' => $count < count(Gateway::$alternate) + 1,
            'title' => trans('texts.online_payments'),
            'tokenBillingOptions' => $tokenBillingOptions,
            'currency' => Utils::getFromCache(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY), 'currencies'),
            'taxRates' => TaxRate::scope()->whereIsInclusive(false)->orderBy('rate')->get(['public_id', 'name', 'rate']),
            'account' => $account,
        ]);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showProducts()
    {
        $data = [
            'account' => Auth::user()->account,
            'title' => trans('texts.product_library'),
        ];

        return View::make('accounts.products', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showTaxRates()
    {
        $data = [
            'account' => Auth::user()->account,
            'title' => trans('texts.tax_rates'),
            'taxRates' => TaxRate::scope()->whereIsInclusive(false)->get(),
            'countInvoices' => Invoice::scope()->withTrashed()->count(),
            'hasInclusiveTaxRates' => TaxRate::scope()->whereIsInclusive(true)->count() ? true : false,
        ];

        return View::make('accounts.tax_rates', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showPaymentTerms()
    {
        $data = [
            'account' => Auth::user()->account,
            'title' => trans('texts.payment_terms'),
        ];

        return View::make('accounts.payment_terms', $data);
    }

    /**
     * @param $section
     *
     * @return \Illuminate\Contracts\View\View
     */
    private function showInvoiceDesign($section)
    {
        $account = Auth::user()->account->load('country');

        if ($invoice = Invoice::scope()->invoices()->orderBy('id')->first()) {
            $invoice->load('account', 'client.contacts', 'invoice_items');
            $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
            $invoice->due_date = Utils::fromSqlDate($invoice->due_date);
        } else {
            $client = new stdClass();
            $contact = new stdClass();
            $invoiceItem = new stdClass();
            $document = new stdClass();

            $client->name = 'Sample Client';
            $client->address1 = '10 Main St.';
            $client->city = 'New York';
            $client->state = 'NY';
            $client->postal_code = '10000';
            $client->work_phone = '(212) 555-0000';
            $client->work_email = 'sample@example.com';
            $client->balance = 100;
            $client->vat_number = $account->vat_number ? '1234567890' : '';
            $client->id_number = $account->id_number ? '1234567890' : '';

            if ($account->customLabel('client1')) {
                $client->custom_value1 = '0000';
            }
            if ($account->customLabel('client2')) {
                $client->custom_value2 = '0000';
            }

            $invoice = new stdClass();
            $invoice->invoice_number = '0000';
            $invoice->invoice_date = Utils::fromSqlDate(date('Y-m-d'));
            $invoice->account = json_decode($account->toJson());
            $invoice->amount = $invoice->balance = 100;

            if ($account->customLabel('invoice_text1')) {
                $invoice->custom_text_value1 = '0000';
            }
            if ($account->customLabel('invoice_text2')) {
                $invoice->custom_text_value2 = '0000';
            }

            $invoice->terms = trim($account->invoice_terms);
            $invoice->invoice_footer = trim($account->invoice_footer);

            $contact->first_name = 'Test';
            $contact->last_name = 'Contact';
            $contact->email = 'contact@gmail.com';
            $client->contacts = [$contact];

            $invoiceItem->cost = 100;
            $invoiceItem->qty = 1;
            $invoiceItem->notes = 'Notes';
            $invoiceItem->product_key = 'Item';
            $invoiceItem->discount = 10;
            $invoiceItem->tax_name1 = 'Tax';
            $invoiceItem->tax_rate1 = 10;

            if ($account->customLabel('product1')) {
                $invoiceItem->custom_value1 = '0000';
            }
            if ($account->customLabel('product2')) {
                $invoiceItem->custom_value2 = '0000';
            }

            $document->base64 = 'data:image/jpeg;base64, ';

            $invoice->client = $client;
            $invoice->invoice_items = [$invoiceItem];
            //$invoice->documents = $account->hasFeature(FEATURE_DOCUMENTS) ? [$document] : [];
            $invoice->documents = [];
        }

        $data['account'] = $account;
        $data['invoice'] = $invoice;
        $data['invoiceLabels'] = json_decode($account->invoice_labels) ?: [];
        $data['title'] = trans('texts.invoice_design');
        $data['invoiceDesigns'] = InvoiceDesign::getDesigns();
        $data['invoiceFonts'] = Cache::get('fonts');
        $data['section'] = $section;
        $data['pageSizes'] = array_combine(InvoiceDesign::$pageSizes, InvoiceDesign::$pageSizes);

        $design = false;
        foreach ($data['invoiceDesigns'] as $item) {
            if ($item->id == $account->invoice_design_id) {
                $design = $item->javascript;
                break;
            }
        }

        if ($section == ACCOUNT_CUSTOMIZE_DESIGN) {
            if ($custom = $account->getCustomDesign(request()->design_id)) {
                $data['customDesign'] = $custom;
            } else {
                $data['customDesign'] = $design;
            }
        }

        return View::make("accounts.{$section}", $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showClientPortal()
    {
        $account = Auth::user()->account->load('country');
        $css = $account->client_view_css ? $account->client_view_css : '';

        if (Utils::isNinja() && $css) {
            // Unescape the CSS for display purposes
            $css = str_replace(
                ['\3C ', '\3E ', '\26 '],
                ['<', '>', '&'],
                $css
            );
        }

        $types = [
            GATEWAY_TYPE_CREDIT_CARD,
            GATEWAY_TYPE_BANK_TRANSFER,
            GATEWAY_TYPE_PAYPAL,
            GATEWAY_TYPE_BITCOIN,
            GATEWAY_TYPE_DWOLLA,
        ];
        $options = [];
        foreach ($types as $type) {
            if ($account->getGatewayByType($type)) {
                $alias = GatewayType::getAliasFromId($type);
                $options[$alias] = trans("texts.{$alias}");
            }
        }

        $data = [
            'client_view_css' => $css,
            'enable_portal_password' => $account->enable_portal_password,
            'send_portal_password' => $account->send_portal_password,
            'title' => trans('texts.client_portal'),
            'section' => ACCOUNT_CLIENT_PORTAL,
            'account' => $account,
            'products' => Product::scope()->orderBy('product_key')->get(),
            'gateway_types' => $options,
        ];

        return View::make('accounts.client_portal', $data);
    }

    /**
     * @return \Illuminate\Contracts\View\View
     */
    private function showTemplates()
    {
        $account = Auth::user()->account->load('country');
        $data['account'] = $account;
        $data['templates'] = [];
        $data['defaultTemplates'] = [];
        foreach (AccountEmailSettings::$templates as $type) {
            $data['templates'][$type] = [
                'subject' => $account->getEmailSubject($type),
                'template' => $account->getEmailTemplate($type),
            ];
            $data['defaultTemplates'][$type] = [
                'subject' => $account->getDefaultEmailSubject($type),
                'template' => $account->getDefaultEmailTemplate($type),
            ];
        }
        $data['title'] = trans('texts.email_templates');

        return View::make('accounts.templates_and_reminders', $data);
    }

    /**
     * @param $section
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function doSection($section)
    {
        if ($section === ACCOUNT_LOCALIZATION) {
            return self::saveLocalization();
        } elseif ($section == ACCOUNT_PAYMENTS) {
            return self::saveOnlinePayments();
        } elseif ($section === ACCOUNT_NOTIFICATIONS) {
            return self::saveNotifications();
        } elseif ($section === ACCOUNT_EXPORT) {
            return self::export();
        } elseif ($section === ACCOUNT_INVOICE_SETTINGS) {
            return self::saveInvoiceSettings();
        } elseif ($section === ACCOUNT_INVOICE_DESIGN) {
            return self::saveInvoiceDesign();
        } elseif ($section === ACCOUNT_CUSTOMIZE_DESIGN) {
            return self::saveCustomizeDesign();
        } elseif ($section === ACCOUNT_TEMPLATES_AND_REMINDERS) {
            return self::saveEmailTemplates();
        } elseif ($section === ACCOUNT_PRODUCTS) {
            return self::saveProducts();
        } elseif ($section === ACCOUNT_TAX_RATES) {
            return self::saveTaxRates();
        } elseif ($section === ACCOUNT_PAYMENT_TERMS) {
            return self::savePaymetTerms();
        } elseif ($section === ACCOUNT_MANAGEMENT) {
            return self::saveAccountManagement();
        }
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveAccountManagement()
    {
        $user = Auth::user();
        $account = $user->account;
        $modules = Input::get('modules');

        if (Utils::isSelfHost()) {
            // get all custom modules, including disabled
            $custom_modules = collect(Input::get('custom_modules'))->each(function ($item, $key) {
                $module = Module::find($item);
                if ($module && $module->disabled()) {
                    $module->enable();
                }
            });

            (Module::toCollection()->diff($custom_modules))->each(function ($item, $key) {
                if ($item->enabled()) {
                    $item->disable();
                }
            });
        }

        $user->force_pdfjs = Input::get('force_pdfjs') ? true : false;
        $user->save();

        $account->live_preview = Input::get('live_preview') ? true : false;

        // Automatically disable live preview when using a large font
        $fonts = Cache::get('fonts')->filter(function ($font) use ($account) {
            if ($font->google_font) {
                return false;
            }

            return $font->id == $account->header_font_id || $font->id == $account->body_font_id;
        });
        if ($account->live_preview && $fonts->count()) {
            $account->live_preview = false;
            Session::flash('warning', trans('texts.live_preview_disabled'));
        }

        $account->enabled_modules = $modules ? array_sum($modules) : 0;
        $account->save();

        Session::flash('message', trans('texts.updated_settings'));

        return Redirect::to('settings/'.ACCOUNT_MANAGEMENT);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveCustomizeDesign()
    {
        $designId = intval(Input::get('design_id')) ?: CUSTOM_DESIGN1;
        $field = 'custom_design' . ($designId - 10);

        if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) {
            $account = Auth::user()->account;
            if (! $account->custom_design1) {
                $account->invoice_design_id = CUSTOM_DESIGN1;
            }
            $account->$field = Input::get('custom_design');
            $account->save();

            Session::flash('message', trans('texts.updated_settings'));
        }

        return Redirect::to('settings/' . ACCOUNT_CUSTOMIZE_DESIGN . '?design_id=' . $designId);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    public function saveClientPortalSettings(SaveClientPortalSettings $request)
    {
        $account = $request->user()->account;

        // check subdomain is unique in the lookup tables
        if (request()->subdomain) {
            if (! \App\Models\LookupAccount::validateField('subdomain', request()->subdomain, $account)) {
                return Redirect::to('settings/' . ACCOUNT_CLIENT_PORTAL)
                    ->withError(trans('texts.subdomain_taken'))
                    ->withInput();
            }
        }


        (bool) $fireUpdateSubdomainEvent = false;

        if ($account->subdomain !== $request->subdomain) {
            $fireUpdateSubdomainEvent = true;
            event(new SubdomainWasRemoved($account));
        }

        $account->fill($request->all());
        $account->client_view_css = $request->client_view_css;
        $account->subdomain = $request->subdomain;
        $account->iframe_url = $request->iframe_url;
        $account->is_custom_domain = $request->is_custom_domain;
        $account->save();

        if ($fireUpdateSubdomainEvent) {
            event(new SubdomainWasUpdated($account));
        }


        return redirect('settings/' . ACCOUNT_CLIENT_PORTAL)
            ->with('message', trans('texts.updated_settings'));
    }

    /**
     * @return $this|\Illuminate\Http\RedirectResponse
     */
    public function saveEmailSettings(SaveEmailSettings $request)
    {
        $account = $request->user()->account;
        $account->fill($request->all());
        $account->save();

        $settings = $account->account_email_settings;
        $settings->fill($request->all());
        $settings->save();

        return redirect('settings/' . ACCOUNT_EMAIL_SETTINGS)
            ->with('message', trans('texts.updated_settings'));
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveEmailTemplates()
    {
        if (Auth::user()->account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
            $account = Auth::user()->account;

            foreach (AccountEmailSettings::$templates as $type) {
                $subjectField = "email_subject_{$type}";
                $subject = Input::get($subjectField, $account->getEmailSubject($type));
                $account->account_email_settings->$subjectField = ($subject == $account->getDefaultEmailSubject($type) ? null : $subject);

                $bodyField = "email_template_{$type}";
                $body = Input::get($bodyField, $account->getEmailTemplate($type));
                $account->account_email_settings->$bodyField = ($body == $account->getDefaultEmailTemplate($type) ? null : $body);
            }

            foreach ([TEMPLATE_REMINDER1, TEMPLATE_REMINDER2, TEMPLATE_REMINDER3] as $type) {
                $enableField = "enable_{$type}";
                $account->$enableField = Input::get($enableField) ? true : false;
                $account->{"num_days_{$type}"} = Input::get("num_days_{$type}");
                $account->{"field_{$type}"} = Input::get("field_{$type}");
                $account->{"direction_{$type}"} = Input::get("field_{$type}") == REMINDER_FIELD_INVOICE_DATE ? REMINDER_DIRECTION_AFTER : Input::get("direction_{$type}");

                $number = preg_replace('/[^0-9]/', '', $type);
                $account->account_email_settings->{"late_fee{$number}_amount"} = Input::get("late_fee{$number}_amount");
                $account->account_email_settings->{"late_fee{$number}_percent"} = Input::get("late_fee{$number}_percent");
            }

            $account->enable_reminder4 = Input::get('enable_reminder4') ? true : false;
            $account->account_email_settings->frequency_id_reminder4 = Input::get('frequency_id_reminder4');

            $account->save();
            $account->account_email_settings->save();

            Session::flash('message', trans('texts.updated_settings'));
        }

        return Redirect::to('settings/'.ACCOUNT_TEMPLATES_AND_REMINDERS);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveTaxRates()
    {
        $account = Auth::user()->account;
        $account->fill(Input::all());
        $account->save();

        Session::flash('message', trans('texts.updated_settings'));

        return Redirect::to('settings/'.ACCOUNT_TAX_RATES);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveProducts()
    {
        $account = Auth::user()->account;

        $account->show_product_notes = Input::get('show_product_notes') ? true : false;
        $account->fill_products = Input::get('fill_products') ? true : false;
        $account->update_products = Input::get('update_products') ? true : false;
        $account->convert_products = Input::get('convert_products') ? true : false;
        $account->save();

        Session::flash('message', trans('texts.updated_settings'));

        return Redirect::to('settings/'.ACCOUNT_PRODUCTS);
    }

    /**
     * @return $this|\Illuminate\Http\RedirectResponse
     */
    private function saveInvoiceSettings()
    {
        if (Auth::user()->account->hasFeature(FEATURE_INVOICE_SETTINGS)) {
            $rules = [];
            foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_CLIENT] as $entityType) {
                if (Input::get("{$entityType}_number_type") == 'pattern') {
                    $rules["{$entityType}_number_pattern"] = 'has_counter';
                }
            }
            if (Input::get('credit_number_enabled')) {
                $rules['credit_number_prefix'] = 'required_without:credit_number_pattern';
                $rules['credit_number_pattern'] = 'required_without:credit_number_prefix';
            }
            $validator = Validator::make(Input::all(), $rules);

            if ($validator->fails()) {
                return Redirect::to('settings/'.ACCOUNT_INVOICE_SETTINGS)
                    ->withErrors($validator)
                    ->withInput();
            } else {
                $account = Auth::user()->account;
                $account->custom_value1 = Input::get('custom_value1');
                $account->custom_value2 = Input::get('custom_value2');
                $account->custom_invoice_taxes1 = Input::get('custom_invoice_taxes1') ? true : false;
                $account->custom_invoice_taxes2 = Input::get('custom_invoice_taxes2') ? true : false;
                $account->custom_fields = request()->custom_fields;
                $account->invoice_number_padding = Input::get('invoice_number_padding');
                $account->invoice_number_counter = Input::get('invoice_number_counter');
                $account->quote_number_prefix = Input::get('quote_number_prefix');
                $account->share_counter = Input::get('share_counter') ? true : false;
                $account->invoice_terms = Input::get('invoice_terms');
                $account->invoice_footer = Input::get('invoice_footer');
                $account->quote_terms = Input::get('quote_terms');
                $account->auto_convert_quote = Input::get('auto_convert_quote');
                $account->auto_archive_quote = Input::get('auto_archive_quote');
                $account->auto_archive_invoice = Input::get('auto_archive_invoice');
                $account->auto_email_invoice = Input::get('auto_email_invoice');
                $account->recurring_invoice_number_prefix = Input::get('recurring_invoice_number_prefix');

                $account->client_number_prefix = trim(Input::get('client_number_prefix'));
                $account->client_number_pattern = trim(Input::get('client_number_pattern'));
                $account->client_number_counter = Input::get('client_number_counter');
                $account->credit_number_counter = Input::get('credit_number_counter');
                $account->credit_number_prefix = trim(Input::get('credit_number_prefix'));
                $account->credit_number_pattern = trim(Input::get('credit_number_pattern'));
                $account->reset_counter_frequency_id = Input::get('reset_counter_frequency_id');
                $account->reset_counter_date = $account->reset_counter_frequency_id ? Utils::toSqlDate(Input::get('reset_counter_date')) : null;

                if (Input::has('recurring_hour')) {
                    $account->recurring_hour = Input::get('recurring_hour');
                }

                if (! $account->share_counter) {
                    $account->quote_number_counter = Input::get('quote_number_counter');
                }

                foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_CLIENT] as $entityType) {
                    if (Input::get("{$entityType}_number_type") == 'prefix') {
                        $account->{"{$entityType}_number_prefix"} = trim(Input::get("{$entityType}_number_prefix"));
                        $account->{"{$entityType}_number_pattern"} = null;
                    } else {
                        $account->{"{$entityType}_number_pattern"} = trim(Input::get("{$entityType}_number_pattern"));
                        $account->{"{$entityType}_number_prefix"} = null;
                    }
                }

                if (! $account->share_counter
                    && $account->invoice_number_prefix == $account->quote_number_prefix
                    && $account->invoice_number_pattern == $account->quote_number_pattern) {
                    Session::flash('error', trans('texts.invalid_counter'));

                    return Redirect::to('settings/'.ACCOUNT_INVOICE_SETTINGS)->withInput();
                } else {
                    $account->save();
                    Session::flash('message', trans('texts.updated_settings'));
                }
            }
        }

        return Redirect::to('settings/'.ACCOUNT_INVOICE_SETTINGS);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveInvoiceDesign()
    {
        if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) {
            $account = Auth::user()->account;
            $account->hide_quantity = Input::get('hide_quantity') ? true : false;
            $account->hide_paid_to_date = Input::get('hide_paid_to_date') ? true : false;
            $account->all_pages_header = Input::get('all_pages_header') ? true : false;
            $account->all_pages_footer = Input::get('all_pages_footer') ? true : false;
            $account->invoice_embed_documents = Input::get('invoice_embed_documents') ? true : false;
            $account->header_font_id = Input::get('header_font_id');
            $account->body_font_id = Input::get('body_font_id');
            $account->primary_color = Input::get('primary_color');
            $account->secondary_color = Input::get('secondary_color');
            $account->invoice_design_id = Input::get('invoice_design_id');
            $account->quote_design_id = Input::get('quote_design_id');
            $account->font_size = intval(Input::get('font_size'));
            $account->page_size = Input::get('page_size');
            $account->background_image_id = Document::getPrivateId(request()->background_image_id);

            $labels = [];
            foreach (Account::$customLabels as $field) {
                $labels[$field] = Input::get("labels_{$field}");
            }
            $account->invoice_labels = json_encode($labels);
            $account->invoice_fields = Input::get('invoice_fields_json');

            $account->save();

            Session::flash('message', trans('texts.updated_settings'));
        }

        return Redirect::to('settings/'.ACCOUNT_INVOICE_DESIGN);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveNotifications()
    {
        $user = Auth::user();
        $user->notify_sent = Input::get('notify_sent');
        $user->notify_viewed = Input::get('notify_viewed');
        $user->notify_paid = Input::get('notify_paid');
        $user->notify_approved = Input::get('notify_approved');
        $user->only_notify_owned = Input::get('only_notify_owned');
        $user->slack_webhook_url = Input::get('slack_webhook_url');
        $user->save();

        $account = $user->account;
        $account->fill(request()->all());
        $account->save();

        Session::flash('message', trans('texts.updated_settings'));

        return Redirect::to('settings/'.ACCOUNT_NOTIFICATIONS);
    }

    /**
     * @param UpdateAccountRequest $request
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function updateDetails(UpdateAccountRequest $request)
    {
        $account = Auth::user()->account;
        $this->accountRepo->save($request->input(), $account);

        /* Logo image file */
        if ($uploaded = Input::file('logo')) {
            $path = Input::file('logo')->getRealPath();
            $disk = $account->getLogoDisk();
            $extension = strtolower($uploaded->getClientOriginalExtension());

            if (empty(Document::$types[$extension]) && ! empty(Document::$extraExtensions[$extension])) {
                $documentType = Document::$extraExtensions[$extension];
            } else {
                $documentType = $extension;
            }

            if (! in_array($documentType, ['jpeg', 'png', 'gif'])) {
                Session::flash('warning', 'Unsupported file type');
            } else {
                $documentTypeData = Document::$types[$documentType];

                $filePath = $uploaded->path();
                $size = filesize($filePath);

                if ($size / 1000 > MAX_DOCUMENT_SIZE) {
                    Session::flash('error', trans('texts.logo_warning_too_large'));
                } else {
                    if ($documentType != 'gif') {
                        $account->logo = $account->account_key.'.'.$documentType;

                        try {
                            $imageSize = getimagesize($filePath);
                            $account->logo_width = $imageSize[0];
                            $account->logo_height = $imageSize[1];
                            $account->logo_size = $size;

                            // make sure image isn't interlaced
                            if (extension_loaded('fileinfo')) {
                                $image = Image::make($path);
                                $image->interlace(false);
                                $imageStr = (string) $image->encode($documentType);
                                $disk->put($account->logo, $imageStr);
                                $account->logo_size = strlen($imageStr);
                            } else {
                                if (Utils::isInterlaced($filePath)) {
                                    $account->clearLogo();
                                    Session::flash('error', trans('texts.logo_warning_invalid'));
                                } else {
                                    $stream = fopen($filePath, 'r');
                                    $disk->getDriver()->putStream($account->logo, $stream, ['mimetype' => $documentTypeData['mime']]);
                                    fclose($stream);
                                }
                            }
                        } catch (Exception $exception) {
                            $account->clearLogo();
                            Session::flash('error', trans('texts.logo_warning_invalid'));
                        }
                    } else {
                        if (extension_loaded('fileinfo')) {
                            $account->logo = $account->account_key.'.png';
                            $image = Image::make($path);
                            $image = Image::canvas($image->width(), $image->height(), '#FFFFFF')->insert($image);
                            $imageStr = (string) $image->encode('png');
                            $disk->put($account->logo, $imageStr);

                            $account->logo_size = strlen($imageStr);
                            $account->logo_width = $image->width();
                            $account->logo_height = $image->height();
                        } else {
                            Session::flash('error', trans('texts.logo_warning_fileinfo'));
                        }
                    }
                }
            }

            $account->save();
        }

        event(new UserSettingsChanged());

        Session::flash('message', trans('texts.updated_settings'));

        return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS);
    }

    /**
     * @return $this|\Illuminate\Http\RedirectResponse
     */
    public function saveUserDetails()
    {
        /** @var \App\Models\User $user */
        $user = Auth::user();
        $email = trim(strtolower(Input::get('email')));

        if (! \App\Models\LookupUser::validateField('email', $email, $user)) {
            return Redirect::to('settings/' . ACCOUNT_USER_DETAILS)
                ->withError(trans('texts.email_taken'))
                ->withInput();
        }

        $rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id'];

        if ($user->google_2fa_secret) {
            $rules['phone'] = 'required';
        }

        $validator = Validator::make(Input::all(), $rules);

        if ($validator->fails()) {
            return Redirect::to('settings/'.ACCOUNT_USER_DETAILS)
                ->withErrors($validator)
                ->withInput();
        } else {
            $user->first_name = trim(Input::get('first_name'));
            $user->last_name = trim(Input::get('last_name'));
            $user->username = $email;
            $user->email = $email;
            $user->phone = trim(Input::get('phone'));
            $user->dark_mode = Input::get('dark_mode');

            if (! Auth::user()->is_admin) {
                $user->notify_sent = Input::get('notify_sent');
                $user->notify_viewed = Input::get('notify_viewed');
                $user->notify_paid = Input::get('notify_paid');
                $user->notify_approved = Input::get('notify_approved');
                $user->only_notify_owned = Input::get('only_notify_owned');
            }

            if ($user->google_2fa_secret && ! Input::get('enable_two_factor')) {
                $user->google_2fa_secret = null;
            }

            if (Utils::isNinja()) {
                if (Input::get('referral_code') && ! $user->referral_code) {
                    $user->referral_code = strtolower(str_random(RANDOM_KEY_LENGTH));
                }
            }

            $user->save();

            event(new UserSettingsChanged());
            Session::flash('message', trans('texts.updated_settings'));

            return Redirect::to('settings/'.ACCOUNT_USER_DETAILS);
        }
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveLocalization()
    {
        /** @var \App\Models\Account $account */
        $account = Auth::user()->account;

        $account->timezone_id = Input::get('timezone_id') ? Input::get('timezone_id') : null;
        $account->date_format_id = Input::get('date_format_id') ? Input::get('date_format_id') : null;
        $account->datetime_format_id = Input::get('datetime_format_id') ? Input::get('datetime_format_id') : null;
        $account->currency_id = Input::get('currency_id') ? Input::get('currency_id') : 1; // US Dollar
        $account->language_id = Input::get('language_id') ? Input::get('language_id') : 1; // English
        $account->military_time = Input::get('military_time') ? true : false;
        $account->show_currency_code = Input::get('show_currency_code') ? true : false;
        $account->start_of_week = Input::get('start_of_week') ? Input::get('start_of_week') : 0;
        $account->financial_year_start = Input::get('financial_year_start') ? Input::get('financial_year_start') : null;
        $account->save();

        event(new UserSettingsChanged());

        Session::flash('message', trans('texts.updated_settings'));

        return Redirect::to('settings/'.ACCOUNT_LOCALIZATION);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    private function saveOnlinePayments()
    {
        $account = Auth::user()->account;
        $account->token_billing_type_id = Input::get('token_billing_type_id');
        $account->auto_bill_on_due_date = boolval(Input::get('auto_bill_on_due_date'));
        $account->gateway_fee_enabled = boolval(Input::get('gateway_fee_enabled'));
        $account->send_item_details = boolval(Input::get('send_item_details'));

        $account->save();

        event(new UserSettingsChanged());

        Session::flash('message', trans('texts.updated_settings'));

        return Redirect::to('settings/'.ACCOUNT_PAYMENTS);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    public function removeLogo()
    {
        $account = Auth::user()->account;

        if (! Utils::isNinjaProd() && $account->hasLogo()) {
            $account->getLogoDisk()->delete($account->logo);
        }

        $account->logo = null;
        $account->logo_size = null;
        $account->logo_width = null;
        $account->logo_height = null;
        $account->save();

        Session::flash('message', trans('texts.removed_logo'));

        return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS);
    }

    /**
     * @return string
     */
    public function checkEmail()
    {
        $email = trim(strtolower(Input::get('email')));
        $user = Auth::user();

        if (! \App\Models\LookupUser::validateField('email', $email, $user)) {
            return 'taken';
        }

        $email = User::withTrashed()->where('email', '=', $email)
            ->where('id', '<>', $user->registered ? 0 : $user->id)
            ->first();

        if ($email) {
            return 'taken';
        } else {
            return 'available';
        }
    }

    /**
     * @return string
     */
    public function submitSignup()
    {
        $user = Auth::user();
        $ip = Request::getClientIp();
        $account = $user->account;

        $rules = [
            'new_first_name' => 'required',
            'new_last_name' => 'required',
            'new_password' => 'required|min:6',
            'new_email' => 'email|required|unique:users,email',
        ];

        if (! $user->registered) {
            $rules['new_email'] .= ',' . Auth::user()->id . ',id';
        }

        $validator = Validator::make(Input::all(), $rules);

        if ($validator->fails()) {
            return '';
        }

        $firstName = trim(Input::get('new_first_name'));
        $lastName = trim(Input::get('new_last_name'));
        $email = trim(strtolower(Input::get('new_email')));
        $password = trim(Input::get('new_password'));

        if (! \App\Models\LookupUser::validateField('email', $email, $user)) {
            return '';
        }

        if ($user->registered) {
            $newAccount = $this->accountRepo->create($firstName, $lastName, $email, $password, $account->company);
            $newUser = $newAccount->users()->first();
            $newUser->acceptLatestTerms($ip)->save();
            $users = $this->accountRepo->associateAccounts($user->id, $newUser->id);

            Session::flash('message', trans('texts.created_new_company'));
            Session::put(SESSION_USER_ACCOUNTS, $users);
            Auth::loginUsingId($newUser->id);

            return RESULT_SUCCESS;
        } else {
            $user->first_name = $firstName;
            $user->last_name = $lastName;
            $user->email = $email;
            $user->username = $user->email;
            $user->password = bcrypt($password);
            $user->registered = true;
            $user->acceptLatestTerms($ip);
            $user->save();

            $user->account->startTrial(PLAN_PRO);

            if (Input::get('go_pro') == 'true') {
                session([REQUESTED_PRO_PLAN => true]);
            }

            return "{$user->first_name} {$user->last_name}";
        }
    }

    /**
     * @return mixed
     */
    public function doRegister()
    {
        $affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first();
        $email = trim(Input::get('email'));

        if (! $email || $email == TEST_USERNAME) {
            return RESULT_FAILURE;
        }

        $license = new License();
        $license->first_name = Input::get('first_name');
        $license->last_name = Input::get('last_name');
        $license->email = $email;
        $license->transaction_reference = Request::getClientIp();
        $license->license_key = Utils::generateLicense();
        $license->affiliate_id = $affiliate->id;
        $license->product_id = PRODUCT_SELF_HOST;
        $license->is_claimed = 1;
        $license->save();

        return RESULT_SUCCESS;
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    public function purgeData()
    {
        $this->dispatch(new \App\Jobs\PurgeAccountData());

        return redirect('/settings/account_management')->withMessage(trans('texts.purge_successful'));
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    public function cancelAccount()
    {
        if ($reason = trim(Input::get('reason'))) {
            $email = Auth::user()->email;
            $name = Auth::user()->getDisplayName();

            $data = [
                'text' => $reason,
            ];

            $subject = 'Invoice Ninja - Canceled Account';

            $this->userMailer->sendTo(env('CONTACT_EMAIL', CONTACT_EMAIL), $email, $name, $subject, 'contact', $data);
        }

        $user = Auth::user();
        $account = Auth::user()->account;

        \Log::info("Canceled Account: {$account->name} - {$user->email}");
        $type = $account->hasMultipleAccounts() ? 'company' : 'account';
        $subject = trans("texts.deleted_{$type}");
        $message = trans("texts.deleted_{$type}_details", ['account' => $account->getDisplayName()]);
        $this->userMailer->sendMessage($user, $subject, $message);

        $refunded = false;
        if (! $account->hasMultipleAccounts()) {
            $company = $account->company;
            $refunded = $company->processRefund(Auth::user());

            $ninjaClient = $this->accountRepo->getNinjaClient($account);
            dispatch(new \App\Jobs\PurgeClientData($ninjaClient));
        }

        Document::scope()->each(function ($item, $key) {
            $item->delete();
        });

        $this->accountRepo->unlinkAccount($account);
        $account->forceDelete();

        Auth::logout();
        Session::flush();

        if ($refunded) {
            Session::flash('warning', trans('texts.plan_refunded'));
        }

        return Redirect::to('/')->with('clearGuestKey', true);
    }

    /**
     * @return \Illuminate\Http\RedirectResponse
     */
    public function resendConfirmation()
    {
        /** @var \App\Models\User $user */
        $user = Auth::user();
        $this->userMailer->sendConfirmation($user);

        return Redirect::to('/settings/'.ACCOUNT_USER_DETAILS)->with('message', trans('texts.confirmation_resent'));
    }

    /**
     * @param $section
     * @param bool $subSection
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function redirectLegacy($section, $subSection = false)
    {
        if ($section === 'details') {
            $section = ACCOUNT_COMPANY_DETAILS;
        } elseif ($section === 'payments') {
            $section = ACCOUNT_PAYMENTS;
        } elseif ($section === 'advanced_settings') {
            $section = $subSection;
            if ($section === 'token_management') {
                $section = ACCOUNT_API_TOKENS;
            }
        }

        if (! in_array($section, array_merge(Account::$basicSettings, Account::$advancedSettings))) {
            $section = ACCOUNT_COMPANY_DETAILS;
        }

        return Redirect::to("/settings/$section/", 301);
    }

    /**
     * @param TemplateService $templateService
     *
     * @return \Illuminate\Http\Response
     */
    public function previewEmail(TemplateService $templateService)
    {
        $template = Input::get('template');
        $invitation = \App\Models\Invitation::scope()
            ->with('invoice.client.contacts')
            ->first();

        if (! $invitation) {
            return trans('texts.create_invoice_for_sample');
        }

        /** @var \App\Models\Account $account */
        $account = Auth::user()->account;
        $invoice = $invitation->invoice;

        // replace the variables with sample data
        $data = [
            'account' => $account,
            'invoice' => $invoice,
            'invitation' => $invitation,
            'link' => $invitation->getLink(),
            'client' => $invoice->client,
            'amount' => $invoice->amount,
        ];

        // create the email view
        $view = 'emails.' . $account->getTemplateView(ENTITY_INVOICE) . '_html';
        $data = array_merge($data, [
            'body' => $templateService->processVariables($template, $data),
            'entityType' => ENTITY_INVOICE,
        ]);

        return Response::view($view, $data);
    }
}
