<?php
/**
 * Class NHSMember
 *
 * @package Mtc\Plugins\NHS\Classes
 * @author Uldis Zvirbulis <uldis.zvirbulis@mtcmedia.co.uk>
 */
namespace Mtc\Plugins\NHS\Classes;

use App\Casts\OptionalEncrypted;
use App\Src\Encryption;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Mtc\Modules\Members\Models\Member;

/**
 * Class NHSMember
 *
 * @package Mtc\Plugins\NHS\Classes
 * @author Uldis Zvirbulis <uldis.zvirbulis@mtcmedia.co.uk>
 */
class NHSMember extends Model
{
    const TYPE_PATIENT = 'patient';
    const TYPE_HCP = 'hcp';
    const TYPE_PROFESSIONAL_CARER = 'professional_carer';
    const TYPE_PRIVATE_CARER = 'private_carer';


    /**
     * The table associated with the model.
     */
    protected $table = 'nhs_members';

    /**
     * Mass assignable attributes
     */
    protected $fillable = [
        'member_id',
        'firstname',
        'lastname',
        'dob',
        'nhs_number',
        'gender',
        'reminder_date',
        'is_pay_for_prescriptions',
        'pay_explanation',
        'exemption_expiry_date',
        'is_property_safe',
        'is_patient',
        'is_professional_carer',
        'is_hcp',
    ];

    protected $casts = [
        'is_pay_for_prescriptions' => 'integer',
        'job_title' => OptionalEncrypted::class,
        'firstname' => OptionalEncrypted::class,
        'lastname' => OptionalEncrypted::class,
        'dob' => OptionalEncrypted::class,
        'nhs_number' => OptionalEncrypted::class,
    ];

    public static $searchable = [
        'firstname',
        'lastname',
        'dob',
        'nhs_number',
    ];

    protected static function boot() : void
    {
        parent::boot();

        self::created(function (self $nhs_member) {
            //$nhs_member->getConsent();
        });

        self::saved(function (self $nhs_member) {
            Event::dispatch('NHSMember@saved', $nhs_member);
            Encryption::updateHashes($nhs_member);
        });
    }


    private $rules = [
        'firstname' => 'required',
        'lastname' => 'required',
        'dob' => 'date',
        'exemption_expiry_date' => 'date | nullable',
    ];

    private $validation_messages = [
        'dob.date' => 'The date of birth is not a valid date.',
    ];

    public function validate()
    {
        return Validator::make($this->attributes, $this->rules, $this->validation_messages);
    }


    /**
     * Relationship to member
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function member()
    {
        return $this->belongsTo(Member::class);
    }

    /**
     * Relationship to Doctor Surgery
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function doctor_surgery()
    {
        return $this->hasOne(NHSMemberDoctorSurgery::class, 'nhs_member_id', 'id');
    }

    public function prescriptions()
    {
        return $this->hasMany(Prescription::class, 'nhs_member_id');
    }

    public function get_pending_prescriptions()
    {
        return $this
            ->prescriptions()
            ->where('nhs_prescriptions.status', Prescription::STATUS_PENDING)
            ->get()
        ;
    }


    public function get_referred_prescriptions()
    {
        $prescriptions = collect();

        foreach ($this->member->referred_members as $rm) {
            $prescriptions = $prescriptions->concat($rm->nhs_member->prescriptions);
        }

        return $prescriptions;
    }


    public function medical_categories()
    {
        return $this->belongsToMany(MedicalCategory::class, 'nhs_members_nhs_medical_categories', 'nhs_member_id');
    }

    /**
     * Get the consent file for NHS member
     */
    public function getConsent()
    {
        if (!$this->consentFileExists()) {
            $this->generateConsentFile();
        }

        return $this->getConsentFileName();
    }

    /**
     * Check if consent file is already generated or does it need to be generated on the fly
     *
     * @return bool
     */
    protected function consentFileExists()
    {
        return file_exists($this->getConsentFileName());
    }

    /**
     * Get the consent file name.
     * This also ensures consent directory exists so file can be saved
     *
     * @return string
     */
    protected function getConsentFileName()
    {
        if (!is_dir(dirname(SITE_PATH) . "/consents/") && !mkdir(dirname(SITE_PATH) . "/consents/")) {
            throw new \RuntimeException(sprintf('Directory "%s" was not created', dirname(SITE_PATH) . "/consents/"));
        }

        return dirname(SITE_PATH) . "/consents/{$this->member_id}-{$this->doctor_surgery_id}.pdf";
    }

    /**
     * Generate the Consent File for member
     * This is done by rendering template and creating a PDF based for it
     */
    protected function generateConsentFile()
    {
        $twig = App::make('twig');
        $html = $twig->render('NHS/consent/template.twig', [
            'nhs_member' => $this
        ]);

        $pdf = new \TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

        $pdf->SetCreator(PDF_CREATOR);
        $pdf->SetAuthor(config('app.name'));
        $pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 006', PDF_HEADER_STRING);
        $pdf->setPrintHeader(false);
        $pdf->setPrintFooter(false);
        $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
        $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
        $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
        $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

        if (@file_exists(__DIR__ . '/lang/eng.php')) {
            require_once __DIR__ . '/lang/eng.php';
            $pdf->setLanguageArray($l);
        }

        $pdf->SetFont('dejavusans', '', 10);

        $pdf->AddPage();
        $pdf->writeHTML($html, true, false, true, false, '');
        $pdf->lastPage();

        $pdf->Output($this->getConsentFileName(), 'F');
    }


    public function set_type($nhs_referrer_type = null)
    {
        switch ($nhs_referrer_type) {
            case self::TYPE_HCP:
                $this->is_patient = 0;
                $this->is_hcp = 1;
                $this->is_professional_carer = 0;
                $this->save();
                break;
            case self::TYPE_PROFESSIONAL_CARER:
                $this->is_patient = 0;
                $this->is_hcp = 0;
                $this->is_professional_carer = 1;
                $this->save();
                break;
            case self::TYPE_PRIVATE_CARER:
                $this->is_patient = 0;
                $this->is_hcp = 0;
                $this->is_professional_carer = 0;
                $this->save();
                break;
            default:
                $this->is_patient = 1;
                $this->is_hcp = 0;
                $this->is_professional_carer = 0;
                $this->save();
                break;
        }
    }


    public function is_referrer()
    {
        return (! $this->is_patient);
    }


    public function is_care_home_staff()
    {
        return (bool)$this->is_professional_carer;
    }


    public function save_from_input(array $data)
    {
        $errors = [];

        $this->firstname = $data['firstname'];
        $this->lastname = $data['lastname'];

        $this->nhs_number = $data['nhs_number'];
        $this->dob = $data['dob'];
        $this->is_pay_for_prescriptions = $data['is_pay_for_prescriptions'];
        $this->is_vulnerable = $data['is_vulnerable'];
        $this->pay_explanation = $data['pay_explanation'];
        $this->exemption_expiry_date = $data['exemption_expiry_date'];

        // Let's save what we can.
        $this->save();


        if (isset($data['medical_categories'])) {
            $medical_category_ids = collect($data['medical_categories'])->pluck('id');
            $this->medical_categories()->sync($medical_category_ids);
        }

        $errors_bag = $this->validate()->errors();
        $errors = \App\FlashMessage::getImplodedMessages($errors_bag);


        // Doctor surgery.

        if ($output = $this->save_doctor_surgery_from_input((array)$data['doctor_surgery'])) {
            $errors['doctor_surgery'] = $output;
        } else {
            if (! $this->doctor_surgery) {
                $errors['doctor_surgery'] = ['id' => "Doctor surgery is required." ];
            }
        }


        return $errors;
    }


    private function save_doctor_surgery_from_input(array $data)
    {
        $errors = [];

        $doctor_surgery = new NHSMemberDoctorSurgery();
        $doctor_surgery->fill($data);

        $errors_bag = $doctor_surgery->validate()->errors();
        if ($errors_bag->count()) {
            $errors = \App\FlashMessage::getImplodedMessages($errors_bag);
        } else {
            if ($this->doctor_surgery) {
                $this->doctor_surgery()->update($doctor_surgery->attributes);
            } else {
                $this->doctor_surgery()->save($doctor_surgery);
                $this->save();
                $this->refresh();
            }
        }

        return $errors;
    }


    public static function get_exemption_proof_file_dir()
    {
        return 'nhs_exemption_proofs';
    }


    public function get_exemption_proof_file_data()
    {
        $file_dir = self::get_exemption_proof_file_dir();
        $file_path = $file_dir . '/' . $this->exemption_proof_file;

        $data = [
            'mime_type' => Storage::mimeType($file_path),
            'content' => base64_encode(Storage::get($file_path)),
        ];

        return $data;
    }


    public function get_exemption_proof_file_url()
    {
        $file_data = $this->get_exemption_proof_file_data();

        $img = "data:{$file_data['mime_type']};base64,{$file_data['content']}";

        return $img;
    }


    public function get_full_name()
    {
        return "{$this->firstname} {$this->lastname}";
    }


    public function get_name_initials()
    {
        return strtoupper($this->firstname[0] . $this->lastname[0]);
    }

    public function get_member_ref()
    {
        return "{$this->member->id}/{$this->id}";
    }
}
