<?php

namespace App\Http\Controllers;

use App\Models\RenewPageVisit;
use App\Models\RenewRequest;
use App\Models\Token;
use App\Services\DomainService;
use App\Services\XeroService;
use Illuminate\Http\Request;
use App\Models\Domain;
use App\Models\XeroCustomer;
use App\Models\NominetPrice;
use App\Models\NotifyEmail;
use Illuminate\Support\Facades\Mail;

class DomainsController extends Controller
{

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function index()
    {
        $domains = Domain::withTrashed()->orderBy('expiry_date', 'asc')->paginate(15);

        return view('domains.index', compact('domains'));
    }

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function unlinked()
    {
        $domains = Domain::where('customer_id', 0)->paginate(15);

        return view('domains.index', compact('domains'));
    }

    /**
     * @return mixed
     */
    public static function getNominetPrice()
    {
      $price = NominetPrice::where('price', '!=', null)->first();
      return $price->price;
    }

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function nominetPrice()
    {
      $price = NominetPrice::where('price', '!=', null)->first();

      return view('domains.edit_nominet_price', compact('price'));
    }

    /**
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     * @throws \Illuminate\Validation\ValidationException
     */
    public function updateNominetPrice(Request $request)
    {
       $this->validate($request, [
          'price' =>'required|between:0,1000000000099.99',
      ]);

      $validatedData = $request->all();
      $price = NominetPrice::where('price', '!=', null)->first();
      $price->price = $validatedData['price'];
      $price->save();

      return view('domains.edit_nominet_price', compact('price'));
    }

    /**
     * @param $id
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function edit($id)
    {
      $domain = Domain::withTrashed()->find($id);
      $customers = XeroCustomer::all();

      return view('domains.edit', compact('domain', 'customers'));
    }

    /**
     * @param Request $request
     * @param $id
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     * @throws \Illuminate\Validation\ValidationException
     */
    public function update(Request $request, $id)
    {
      $this->validate($request, [
          'customer_id' => 'integer',
      ]);

      $validatedData = $request->all();
      $domain = Domain::withTrashed()->find($id);
      $domain->customer_id = $validatedData['customer_id'];
      $domain->save();
      if( $domain->registry == 'nominet' ) {
        $nominetPrice = NominetPrice::where('price', '!=', null)->first();
        $price = $nominetPrice->price;
       }
      if( $domain->registry == 'opensrs' ) {
          $price = DomainService::getOpenSrsPrice( $domain->domain );
      }
      return view('domains.show', compact('domain','price'));
    }

    /**
     *  import Possible Periods
     */
    public function importPossiblePeriods()
    {
        $file = fopen(storage_path('app/open_srs_chart.csv'), 'r');
        while (($line = fgetcsv($file)) !== FALSE) {
            if( $line[0] != 'TLD' ) {
                $periods = $line[20];
                $periodsArray = explode(' to ', $periods);
                $arrayToJson = [];
                if( count($periodsArray) > 1 ){

                    if( $periodsArray[1] != '5, 10 ' ) {

                        $i = (int)$periodsArray[0];

                        while ($i <= $periodsArray[1]) {
                            $arrayToJson[] = (int)$i;
                            $i++;
                        }
                    } else {
                        $i = $periodsArray[0];
                        while ($i <= 5) {
                            $arrayToJson[] = (int)$i;
                            $i++;
                        }
                        $arrayToJson[] = 10;
                    }
                } else {
                    if( $periodsArray[0] != '1, 2, 5, or 10 ' ) {
                        $arrayToJson[] = (int)$periodsArray[0];
                    } else {
                        $arrayToJson = [1,2,5,10];
                    }
                }
                echo "<pre>";
                print_r($arrayToJson);
                echo "</pre>";
            }

        }
        fclose($file);
    }

    /**
     * @param $id
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function show($id)
    {
      $domain = Domain::withTrashed()->find($id);;
       if( $domain->registry == 'nominet' ) {
        $nominetPrice = NominetPrice::where('price', '!=', null)->first();
        $price = $nominetPrice->price;
       }
      if( $domain->registry == 'opensrs' ) {
          $price = DomainService::getOpenSrsPrice( $domain->domain );
      }
      return view('domains.show', compact('domain', 'price'));
    }

    /**
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     * @throws \Illuminate\Validation\ValidationException
     */
    public function search(Request $request)
    {
        $this->validate($request, [
             'search' => 'string',
        ]);
        $validatedData = $request->all();
        $domains = Domain::where('domain', 'like', '%' . $validatedData['search'] . '%')
            ->orWhereHas('customer', function ($query) use ($validatedData) {
                return $query->where('xero_name', 'like', '%' . $validatedData['search'] . '%');
            })->withTrashed()
            ->get();
        $search_query = $validatedData['search'];
        return view('domains.search', compact('domains', 'search_query'));
    }

    /**
     * @param Request $request
     * @param $id
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function viewNotifyEmail(Request $request, $id)
    {
      $notifyEmail = NotifyEmail::find($id);
      return view('domains.notify_email', compact('notifyEmail'));
    }

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function thankYou()
    {
      return view('renew.thank_you');
    }

    /**
     *
     */
    public function importNominet()
    {
        DomainService::importNominet();
    }

    /**
     *
     */
    public function importOpensrs()
    {
        DomainService::importOpensrs();
    }

    /**
     *  Notify Expired domains
     */
    public function notifyExpiry()
    {
        $domains = Domain::where('deleted_at', null)->where('is_renewed', 0)->where('do_not_renew', 0)->get();
        $notifyArray = [];
        foreach ($domains as $key => $domain) {
            $expiry_date_Object = \DateTime::createFromFormat('Y-m-d', $domain->expiry_date);
            $current_date_Object = new \DateTime();
            if( $expiry_date_Object > $current_date_Object ) {
                $interval = $expiry_date_Object->diff($current_date_Object)->format("%a");
                if( $interval == 90 || $interval == 60 || $interval == 30 || $interval == 14 || $interval == 7 ) {
                    $notifyArray[] = $domain->customer_id;
                }
            } else {
                $interval = $expiry_date_Object->diff($current_date_Object)->format("%a");
                if( $interval == 7 || $interval == 14 || $interval == 21 || $interval == 28 ) {
                    $notifyArray[] = $domain->customer_id;
                }
            }
        }

        $notifyArray = array_unique($notifyArray);
        foreach ($notifyArray as $key => $customer_id) {
            $date_end_search = time() + 8640000; // 100 days ahead
            $date_end_search = date('Y-m-d', $date_end_search);

            $customerDomains = Domain::where('customer_id', $customer_id)
                ->where('expiry_date', '<', $date_end_search)
                ->where('deleted_at', NULL)
                ->where('do_not_renew', 0)
                ->get();

            $days = 0;
            foreach ($customerDomains as $domain) {
                $expiry_date_Object = \DateTime::createFromFormat('Y-m-d', $domain->expiry_date);
                $current_date_Object = new \DateTime();

                if( $expiry_date_Object > $current_date_Object ) {
                    $interval = $expiry_date_Object->diff($current_date_Object)->format("%a");
                }else {
                    $interval = $current_date_Object->diff($expiry_date_Object)->format("%a");
                }
                if( $interval > 0 ) {
                    $days = $interval;
                }
                if( $current_date_Object > $expiry_date_Object ) {
                    $days = '-'.$days;
                }
            }

            $addressants = [];
            $customer = XeroCustomer::find($customer_id);
            $xero = new XeroService();
            $contact = $xero->getXeroContact($customer->xero_contact_id);

            $mainContactName = (string)$contact['Name'];
            $addressants[0]['name'] = $mainContactName;
            $addressants[0]['firstName'] = (string)$contact['FirstName'];
            $addressants[0]['lastName'] = (string)$contact['LastName'];
            $addressants[0]['email'] = (string)$contact['EmailAddress'];

            $persons = (array)$contact['ContactPersons'];

            foreach ($persons as $person) {

                if( isset($person['IncludeInEmails']) && $person['IncludeInEmails'] == 'true') {
                    $addressants[$key+1]['name'] = $mainContactName;
                    $addressants[$key+1]['firstName'] = $person['FirstName'];
                    $addressants[$key+1]['lastName'] = '';
                    if( isset($person['LastName']) && $person['LastName'] != '' ) {
                        $addressants[$key+1]['lastName'] = $person['LastName'];
                    }
                    $addressants[$key+1]['email'] = $person['EmailAddress'];
                }
            }

            $name = str_replace('(DD)', '', $mainContactName);
            $token = Token::where('customer_id', $customer_id )->first();
            if($token){
                foreach ($addressants as $address) {
                    $data['email'] = $address['email'];
                    $data['name'] = $name;
                    $data['token'] = $token->token;
                    $data['domains'] = $customerDomains;
                    $data['firstName'] = $address['firstName'];
                    $jsonToNotify = [];
                    $domains_notify = [];
                    foreach( $data['domains'] as $domain ) {
                        $jsonToNotify[$domain->domain] = $domain->expiry_date;
                        $domains_notify[] = $domain->id;
                    }
                    $notifyEmail = new NotifyEmail;
                    $notifyEmail->name = $name;
                    $notifyEmail->email = $data['email'];
                    $notifyEmail->customer_name = $address['firstName'].' '.$address['lastName'];
                    $notifyEmail->domains_expired = $jsonToNotify;
                    $notifyEmail->save();
                    $notifyEmail->domains()->sync($domains_notify);

                    $data['notifyId'] = $notifyEmail->id;
                    $data['subject'] = 'Important - Domain name renewal notice';
                    if( $days != 0 ) {
                        $data['subject'] .= ' ('.$days.' days)';
                    }
                    Mail::send('emails.renew_notify', ['data' => $data], function ($message) use ($data) {
                        $message->from('hello@thinking.fish', 'Thinking Fish');
                        $message->bcc('pool@thinking.fish', 'Pool Thinking Fish');
                        $message->to($data['email'])->subject($data['subject']);
                    });
                }
            }

        }
    }

    /**
     * @param Request $request
     * @param $token
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function renewPage(Request $request, $token)
    {
        $token = Token::where('token', $token)->first();

        $data['customerDomains'] = Domain::where('customer_id', $token->customer_id)
            ->whereNull('deleted_at')
            ->orderBy('expiry_date', 'asc')
            ->get();

        $xero = new XeroService();
        $contact = $xero->getXeroContact($token->customer->xero_contact_id);

        $name = (string) $contact['Name'];
        $data['name'] = $name;

        if (strpos($name, '(DD)') != false) {
            $data['directDebit'] = true;
        } else {
            $data['directDebit'] = false;
        }

        if($request->get('source') ) {
            $source = $_GET['source'];
            $visit = new RenewPageVisit();
            $visit->ip = $this->getUserIP();
            $visit->notify_email_id = $source;
            $visit->save();
        }
        return view('renew.renew', compact('data'));
    }

    /**
     * @return mixed
     */
    protected function getUserIP()
    {
        if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
            $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
            $_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
        }
        $client  = @$_SERVER['HTTP_CLIENT_IP'];
        $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
        $remote  = $_SERVER['REMOTE_ADDR'];

        if(filter_var($client, FILTER_VALIDATE_IP)) {
            $ip = $client;
        }
        elseif(filter_var($forward, FILTER_VALIDATE_IP)) {
            $ip = $forward;
        }
        else {
            $ip = $remote;
        }
        return $ip;
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     * @throws \Illuminate\Validation\ValidationException
     */
    public function renew(Request $request)
    {
        $rules = [
            'cardNumber' => 'required',
            'cardHolderName' => 'required',
            'cardSecurityNumber' => 'required',
            'expiryMonth' => 'required',
            'expiryYear' => 'required'
        ];

        $customMessages = [
            'cardNumber.required' => 'Card number field is required.',
            'cardHolderName.required' => 'Card holder field is required.',
            'cardSecurityNumber.required' => 'CVV field is required.',
            'expiryMonth.required' => 'Expiry month field is required.',
            'expiryYear.required' => 'Expiry year field is required.',
        ];

        $this->validate($request, $rules, $customMessages);
        $allData = $request->all();
        $renew_data = json_decode($allData['renew_data'], true);

        $requests = [];
        $subtotal = 0;

        foreach ($renew_data['domains'] as $domain => $info) {

            $domainObject = Domain::where('domain', $domain)->first();

            if( $info['period'] == 'do_not_renew' ) {
                $domainObject->do_not_renew = 1;
                $domainObject->save();
            } else {
                if( $domainObject->do_not_renew == 1 && $info['period'] != 'do_not_renew' ) {
                    $domainObject->do_not_renew = 0;
                    $domainObject->save();
                }
            }
            $tax_type = $domainObject->customer->tax_type;

            $renew_data['domains'][$domain]['tax_type'] = $tax_type;
            if( $domainObject->registry == 'nominet' ) {
                $price = NominetPrice::where('price', '!=', null)->first();
                $renew_data['domains'][$domain]['price'] = $price->price*$info['period'];

                $subtotal += $price->price*$info['period'];
            } elseif( $domainObject->registry == 'opensrs' ) {
                $renew_data['domains'][$domain]['price'] = DomainService::getOpenSrsPrice($domainObject->domain)*$info['period'];
                $subtotal += DomainService::getOpenSrsPrice($domainObject->domain)*$info['period'];
            }
            $renew_data['domains'][$domain]['expiry_date'] = $domainObject->expiry_date;
        }
        foreach ($renew_data['domains'] as $domain => $info) {
            $renewRequest = new RenewRequest;
            $renewRequest->renew_data = $renew_data;
            $domainObject = Domain::where('domain', $domain)->first();
            $renewRequest->domain_id = $domainObject->id;
            $renewRequest->save();
            $requests[] = $renewRequest->id;
        }

        if( $tax_type == 'NONE' || $tax_type == 'ECZROUTPUTSERVICES' ) {
            $tax = 0;
        } else {
            $tax = $subtotal*0.2;
        }
        $allData['amount'] = $subtotal+$tax;

        $payment = $this->paymentProcess( $allData );
        foreach ($requests as $key => $id) {
            $requestObject = RenewRequest::find($id);
            if( $payment['result'] == false ) {
                $requestObject->error = 'judopay';
                $errorstring = '';

                foreach ($payment['errors'] as $error) {
                    $errorstring .= $error."\r\n";
                }
                $requestObject->error_text = $errorstring;
                $requestObject->save();
            } else {
                $requestObject->judopay_id = $payment['receiptId'];
                $requestObject->judopay_md = $payment['md'];
                $requestObject->save();
            }
        }

        if( $payment['result'] == false ) {
            return back()->withInput($allData)->withErrors($payment['errors']);
        }

        if( $payment['result'] == true  ) {
            $this->redirect_post( $payment['acsUrl'], $payment['md'], $payment['paReq'] );
        }
    }

    /**
     * @param $acsUrl
     * @param $md
     * @param $PaReq
     */
    private function redirect_post( $acsUrl, $md, $PaReq ) {
        ?>
        <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <script type="text/javascript">
                function closethisasap() {
                    document.forms["redirectpost"].submit();
                }
            </script>
        </head>
        <body onload="closethisasap();">
        <form name="redirectpost" method="post" action="<? echo $acsUrl; ?>">
            <input type="hidden" name="PaReq" value="<?php echo $PaReq ?>">
            <input type="hidden" name="MD" value="<?php echo $md ?>">
            <input type="hidden" name="TermUrl" value="https://thinking.fish/intranet/payment-for-renewal">
        </form>
        </body>
        </html>
        <?php

    }

    /**
     * @param $renewData
     * @return mixed
     */
    public function paymentProcess($renewData)
    {
        $judopay = new \Judopay(
            array(
                'apiToken' => 'OY7LOiJ2pKid42aZ',
                'apiSecret' => 'cac65aca5a85513b2dd38be9c80fead72dba9754635048cd0fb7f942ca62a25d',
                'judoId' => '100771-518',
                'useProduction' => true,
            )
        );

        $payment = $judopay->getModel('Payment');
        $rand_number = rand(0, 1000000000000);
        if( strlen($renewData['expiryYear']) != 2 ) {
            $year = substr($renewData['expiryYear'], 2, 2);
        } else {
            $year = $renewData['expiryYear'];
        }

        $payment->setAttributeValues(
            array(
                'judoId' => '100771-518',
                'yourConsumerReference' => 'alex.vershinin@thinking.fish',
                'yourPaymentReference' => 'Thinking Fish Payment ' . $rand_number,
                'amount' => number_format($renewData['amount'], 2, '.', ''),
                'currency' => 'GBP',
                'cardNumber' => $renewData['cardNumber'],
                'expiryDate' => $renewData['expiryMonth'] .'/'.$year,
                'cv2' => $renewData['cardSecurityNumber']
            )
        );

        try {
            $response = $payment->create();

            if(  $response['result'] == 'Requires 3D Secure' ) {

                $result = $response;
                $result['result'] = true;
            }
        } catch (\Judopay\Exception\ValidationError $e) {
            foreach ($e->getModelErrors() as $key => $object) {
                $result['errors'][] = $object->getMessage();
            }

            $result['message'] = $e->getSummary();
            $result['result'] = false;
        } catch (\Judopay\Exception\ApiException $e) {
            foreach ($e->getFieldErrors() as $key => $object) {
                $result['errors'][] = $object->getMessage();
            }

            $result['result'] = false;
        } catch (\Exception $e) {
            $result['errors'][] =  $e->getMessage();
            $result['result'] = false;
        }

        return $result;
    }

    /**
     * @param Request $request
     */
    public function calculatePrice(Request $request)
    {
        $domains_data = $request->all();
        $renew_data = $domains_data['renew'];
        $result = [];
        $subtotal = 0;
        $opensrsPrice = 0;

        foreach ($renew_data as $domain_id => $renew_period) {
            $domain = Domain::find($domain_id);
            if( $renew_period != 0 && $renew_period  != 'do_not_renew' ) {

                $tax_type = $domain->customer->tax_type;
                $result['domains'][$domain->domain]['period'] = $renew_period;
                if( $domain->registry == 'nominet' ) {

                    $price = NominetPrice::where('price', '!=', null)->first();
                    $result['domains'][$domain->domain]['price'] = $price->price*$renew_period;
                    $subtotal+=$price->price*$renew_period;
                } else {
                    $price = DomainService::getOpenSrsPrice($domain->domain)*$renew_period;
                    $result['domains'][$domain->domain]['price'] = $price;
                    $opensrsPrice+=$price;
                    $subtotal+=$price;
                }
            } elseif( $renew_period  == 'do_not_renew' ) {
                $result['domains'][$domain->domain]['period'] = 'do_not_renew';
                $result['domains'][$domain->domain]['price'] = 0;
            }

        }
        if( $opensrsPrice !=0 ) {
            $ballance = DomainService::checkBallance();
            if( $ballance < $opensrsPrice ) {
                $result['error'] = 'ballance';
                $data['customer'] = $domain->customer->xero_name;
                $data['domains'] = $result['domains'];
                $data['ballance'] = '£'.$ballance;
                $data['opensrsPrice'] =  '£'.number_format($opensrsPrice, 2, '.', '');
                $data['email'] = 'andrew.lobel@thinking.fish';

                Mail::send('emails.opensrs_balance', ['data' => $data], function ($message) use ($data) {
                    $message->from('hello@thinking.fish', 'Thinking Fish');
                    $message->bcc('pool@thinking.fish', 'Pool Thinking Fish');
                    $message->to($data['email'])->subject('OpenSrs low balance');
                });
            }
        }
        if( $tax_type == 'NONE' || $tax_type == 'ECZROUTPUTSERVICES' ) {
            $tax = 0;
        } else {
            $tax = $subtotal*0.2;
        }
        $result['tax'] = $tax;
        $result['subtotal'] = $subtotal;
        $result['total'] = number_format($subtotal+$tax, 2, '.', '');
        echo json_encode($result);

    }

}
