<?php

namespace App;
use App\Http\Controllers\Admin\ConsumerDocument;
use Carbon\Carbon;
use Hashids\Hashids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\URL;


class OnfidoIntegration extends Model{

    use SoftDeletes;


    protected $table = 'onfido';
    private $curl;
    private $baseURL = 'https://api.onfido.com';
    private $APPLICANTS = 'https://api.onfido.com/v3/applicants';
    private $SDK_TOKEN= 'https://api.onfido.com/v3/sdk_token';
    private $listDocument = 'https://api.onfido.com/v3/documents?applicant_id=';
    private $listPhoto = 'https://api.onfido.com/v3/live_photos?applicant_id=';
    private $listVideo = 'https://api.onfido.com/v3/live_videos?applicant_id=';
    private $listChecks = 'https://api.onfido.com/v3/reports?check_id=';
    private $CREATE_CHECK= 'https://api.onfido.com/v3/checks';
    private $application_id = null;

    public function createApplicant($id, $payload){
        $this->callCurl($payload, $this->APPLICANTS);
        $response = $this->getResponse();


        $applicant_id = isset($response['id']) ? $response['id'] : false;

        return $applicant_id ? $this->generatingSDKToken($id, $applicant_id) : $applicant_id;

    }

    public function generatingSDKToken($id, $applicant_id){


        $hashids = new Hashids('Creditfair by CS', 20);
        $hashed_id = $hashids->encode($id);

        $payload = array(
            "applicant_id" => $applicant_id,
            "referrer" =>  URL::to('/').'/esign/id/*'
        );

        $this->callCurl($payload, $this->SDK_TOKEN);
        $response = $this->getResponse();

        $sdk_token = $response['token'];

        return ['token' => $sdk_token, 'applicant_id' => $applicant_id];
    }

    public function createCheck($payload){
        $this->callCurl($payload, $this->CREATE_CHECK);
        $response = $this->getResponse();
        return $response;
    }

    public function getResponse(){
        try {
            $response = curl_exec($this->curl);
            if (curl_error($this->curl)) {
                $error = curl_error($this->curl);
            }
            curl_close($this->curl);

            if (isset($error)) {
                return false;
            }

            return json_decode($response, 1);

        }catch (\Exception $e){

        }
        return false;
    }

    public function callCurl($payload, $url){
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => json_encode($payload),
            CURLOPT_HTTPHEADER => array(
                'Content-Type: application/json',
                'cache-control: no-cache',
                'Authorization: Token token='._env('ONFIDO_SDK_TOKEN')
            ),
        ));

        return $this->curl = $curl;
    }

    public function runOnfido($id, $applicant_type){
        $onfido = OnfidoIntegration::where('application_id',$id)->where('applicant_type', $applicant_type)->orderBy('created_at','desc')->first(['applicant_token_id','check_id', 'applicant_type']);
        if(isset($onfido->applicant_token_id)) {
            if($onfido->applicant_token_id) {
                $this->listDocument($id, $onfido->applicant_token_id, $onfido->applicant_type);
                $this->listLivePhoto($id, $onfido->applicant_token_id, $onfido->applicant_type);
                $this->listLiveVideo($id, $onfido->applicant_token_id, $onfido->applicant_type);
            }
            if($onfido->check_id) {
                $this->listChecks($id, $onfido->check_id, $applicant_type);
            }
        }
    }

    public function listDocument($application_id, $id, $applicant_type){
        $this->application_id = $application_id;
        $response = $this->getLists($this->listDocument.$id, false, $applicant_type, 'list_document');
        if($response && isset($response->documents) && $response->documents) {
            foreach ($response->documents as $item) {
                $this->saveDocument($application_id, $this->downloadDocument($id, $item, $applicant_type), $item, $applicant_type);
            }
        }
        return $response;
    }

    public function listLivePhoto($application_id, $id, $applicant_type){
        $response = $this->getLists($this->listPhoto.$id, false, $applicant_type, 'list_live_photo');
        if($response && isset($response->live_photos) && $response->live_photos) {
            foreach ($response->live_photos as $item) {
                $this->saveDocument($application_id, $this->downloadDocument($id, $item, $applicant_type), $item, 'live_photo');
            }
        }
        return $response;
    }

    public function listLiveVideo($application_id, $id, $applicant_type){
        $response = $this->getLists($this->listVideo.$id, false, $applicant_type, 'list_live_video');
        if($response && isset($response->live_videos) && $response->live_videos) {
            foreach ($response->live_videos as $item) {
                $this->saveDocument($application_id, $this->downloadDocument($id, $item, $applicant_type), $item, $applicant_type, 'live_video');
            }
        }
        return $response;
    }

    public function listChecks($application_id, $id, $applicant_type){
        $response = $this->getLists($this->listChecks.$id, false, $applicant_type, 'list_checks');
        $applicant = ConsumerApplication::where('id', $application_id)->first(['name', 'co_applicant_name']);
        $name = $applicant_type == 1 ? $applicant->name : $applicant->co_applicant_name;
        $doc_type = $applicant_type == 1 ? 'onfido_check_report' : 'co_app_onfido_check_report';
        if(isset($response->reports)) {
            return $this->saveDocument($application_id, $this->buildReport($response->reports, $name), '', $applicant_type, $doc_type);
        }
    }

    public function buildReport($response,$applicant_name){
        $view = view('front.onfido-report', ['data' => $response,'applicant_name'=>$applicant_name]);
        $pdf = App::make('snappy.pdf.wrapper');
        return $pdf->loadHTML($view)->output();
    }

    public function saveOnfidoResponse($type, $response, $applicant_type){
        if($this->application_id) {
            $this->where('application_id', $this->application_id)->where('applicant_type', $applicant_type)->update([$type => $response]);
        }
    }

    public function downloadDocument($id, $item, $applicant_type){
        return $this->getLists($this->baseURL.$item->download_href.'?applicant_id='.$id, true, $applicant_type);
    }

    public function getLists($endpoint, $return, $applicant_type, $type = ''){

        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $endpoint,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'GET',
            CURLOPT_HTTPHEADER => array(
                'Content-Type: application/json',
                'cache-control: no-cache',
                'Authorization: Token token='._env('ONFIDO_SDK_TOKEN')
            ),
        ));

        $response = curl_exec($curl);
        if(!$return)
            $this->saveOnfidoResponse($type, $response, $applicant_type);
        if($return)
            return $response;
        return json_decode($response);
    }

    public function saveDocument($application_id, $file, $item, $applicant_type, $type = ''){
        $file_name = isset($item->type) ? $item->type : '';
        $file_name .= isset($item->side) ? '_'.$item->side : '';
        if($type){$file_name = $type;}

        if($file_name !== 'onfido_check_report' && $file_name !== 'co_app_onfido_check_report'){
            $file_name .= isset($applicant_type) && $applicant_type === 1 ? '_applicant' : (isset($applicant_type) && $applicant_type === 2 ? '_co_applicant' : '');
        }
        (new ConsumerDocument(new Request()))->uploadToS3($file_name, $application_id, $file);
    }
}
