<?php

namespace App\Traits;

use App\Enum\Automation\LogicalOperatorEnum;
use App\Enum\Automation\QueryOperatorEnum;
use App\Enum\ResourceEnum\ModelEnum;
use App\Enum\ResourceEnum\ReviewStatusEnum;
use App\Models\Automation\SmartApproval;
use App\Models\BusinessLocation;
use App\Models\Department;
use App\Models\Performance\Goal;
use App\Models\Position;
use App\Models\Recruitment\InterviewProcess;
use App\Models\Recruitment\JobApplication;
use App\Models\Resources\EmploymentType;
use App\Models\SmartApprovalActivity;
use App\Models\Staff\Staff;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

trait ModelFinder
{

    public function getModelQuery($criterion): string
    {
        $operator = $criterion->operator;
        $column = $criterion->column ?? 'id';

        switch ($operator) {
            case QueryOperatorEnum::IS->value:
                $query = "$column = ?";
                break;
            case QueryOperatorEnum::IS_NOT->value:
                $query = "$column <> ?";
                break;
            case QueryOperatorEnum::IS_EMPTY->value:
                $query = "$column is null OR $column = ''";
                break;
            case QueryOperatorEnum::IS_NOT_EMPTY->value:
                $query = "$column is not null OR $column <> ''";
                break;
            case QueryOperatorEnum::CONTAINS->value:
                $query = "$column in (?)";
                break;
            case QueryOperatorEnum::NOT_CONTAINS->value:
                $query = "$column not in (?)";
                break;
            case QueryOperatorEnum::STARTS_WITH->value:
                $query = "$column ilike CONCAT(?,'%')";
                break;
            case QueryOperatorEnum::ENDS_WITH->value:
                $query = "$column ilike CONCAT('%',?)";
                break;
            case QueryOperatorEnum::AFTER->value:
            case QueryOperatorEnum::GREATER_THAN->value:
                $query = "$column > ?";
                break;
            case QueryOperatorEnum::GREATER_OR_EQUAL->value:
                $query = "$column >= ?";
                break;
            case QueryOperatorEnum::BEFORE->value:
            case QueryOperatorEnum::LESS_THAN->value:
                $query = "$column < ?";
                break;
            case QueryOperatorEnum::LESS_OR_EQUAL->value:
                $query = "$column <= ?";
                break;
            case QueryOperatorEnum::BETWEEN->value:
                $query = "$column between ? and ?";
                break;
            case QueryOperatorEnum::IS_YESTERDAY_DATE->value:
                $query = "DATE($column) = CURRENT_DATE - INTERVAL '1 day'";
                break;
            case QueryOperatorEnum::IS_TODAY_DATE->value:
                $query = "DATE($column) = CURRENT_DATE";
                break;
            case QueryOperatorEnum::IS_TOMORROW_DATE->value:
                $query = "DATE($column) = CURRENT_DATE + INTERVAL '1 day'";
                break;
            default:
                $query = "";
                break;
        }
        return $query;
    }

    public function getModelFromEnum($request_value): ?Builder
    {
        if ($request_value == ModelEnum::EMPLOYMENT_TYPE->value){
            $model = EmploymentType::query();
        }
        elseif ($request_value == ModelEnum::DEPARTMENT->value){
            $model = Department::query();
        }
        elseif ($request_value == ModelEnum::POSITION->value){
            $model = Position::query();
        }
        elseif ($request_value == ModelEnum::STAFF->value){
            $model = Staff::query();
        }
        elseif ($request_value == ModelEnum::USER->value){
            $model = User::query();
        }
        elseif ($request_value == ModelEnum::LOCATION->value){
            $model = BusinessLocation::query();
        }
        elseif ($request_value == ModelEnum::INTERVIEW_PROCESS->value){
            $model = InterviewProcess::query();
        }
        elseif ($request_value == ModelEnum::JOB_APPLICATION->value){
            $model = JobApplication::query();
        }
        elseif ($request_value == ModelEnum::GOALS->value){
            $model = Goal::query();
        }

        return $model ?? null;
    }


    public function getModelClass($request_value): ?string
    {
        if ($request_value == ModelEnum::EMPLOYMENT_TYPE->value){
            $model = EmploymentType::class;
        }
        elseif ($request_value == ModelEnum::DEPARTMENT->value){
            $model = Department::class;
        }
        elseif ($request_value == ModelEnum::POSITION->value){
            $model = Position::class;
        }
        elseif ($request_value == ModelEnum::STAFF->value){
            $model = User::class;
        }
        elseif ($request_value == ModelEnum::LOCATION->value){
            $model = BusinessLocation::class;
        }
        elseif ($request_value == ModelEnum::USER->value){
            $model = User::class;
        }
        elseif ($request_value == ModelEnum::INTERVIEW_PROCESS->value){
            $model = InterviewProcess::class;
        }
        elseif ($request_value == ModelEnum::JOB_APPLICATION->value){
            $model = JobApplication::class;
        }
        elseif ($request_value == ModelEnum::GOALS->value){
            $model = Goal::class;
        }

        return $model ?? Model::class;
    }

    public function userByModel(string $group_type, array $group, int $user_id)
    {
        if ($group_type == ModelEnum::DEPARTMENT->value){
            // Tie to Users
            $model = Department::query()->whereIn('id', $group)->first();
        }
        elseif ($group_type == ModelEnum::POSITION->value){
            // Tie to Users
            $model = Position::query()->whereIn('id', $group)->first();
        }
        elseif ($group_type == ModelEnum::STAFF->value){
            $model = User::query()->whereIn('id', $group)->find($user_id);
        }
        elseif ($group_type == ModelEnum::LOCATION->value){
            // Tie to Users
            $model = BusinessLocation::query()->whereIn('id', $group)->first();
        }

        return $model ?? null;

    }



    public function triggerFlow($service)
    {
        $service_type = get_class((object) $service);
        $service_id = $service?->id;

        // dd($service_type, $service_id, $service);
        $check_exist = SmartApprovalActivity::query()->where([['service_type', '=', $service_type], ['service_id', '=', $service_id]])->first();


        // If service exist, and it's not triggered check criteria & trigger it
        if ($service && !$check_exist){
            $smart_approvals = SmartApproval::query()->whereRelation('smartForm','model_type','=',$service_type)->get();

            $smart_approval = null;
            foreach ($smart_approvals as $key => $approval){
                $criteria_flow = $approval->criteriaFlow;

                if (!empty($criteria_flow)){
                    $expression_result = false;
                    foreach ($criteria_flow as $criterion)
                    {
                        $logic_operator = $criterion->logical_operator ?? null;
                        $model_type = $criterion->model_type;

                        if (class_exists($model_type)) {
                            $model = app($model_type);

                            $values = $criterion->value;
                            $query = $this->getModelQuery($criterion);

                            $criterion_result = (bool) $model->whereRaw($query, $values)->first();

                            if ($logic_operator == 'AND') {
                                $expression_result = $expression_result && $criterion_result;
                            } elseif ($logic_operator == 'OR') {
                                $expression_result = $expression_result || $criterion_result;
                            }
                        }
                        else {
                            throw new \InvalidArgumentException("Class $model_type does not exist.");
                        }
                    }


                    // Met Criteria
                    if ($expression_result){
                        $smart_approval = $approval;
                        break;
                    }
                }

            }


            // Trigger Approval Flow
            if ($smart_approval)
            {
                $process_flow = $smart_approval->approvalProcessFlow()->orderBy('level')->first();
                $activity = SmartApprovalActivity::query()->create([
                    'smart_approval_id' => $smart_approval->id,
                    'process_flow_id' => $process_flow?->id,
                    'status' => ReviewStatusEnum::PENDING->value,
                    'service_type' => $service_type,
                    'service_id' => $service_id,
                ]);
            }
        }

        return $activity ?? null;
    }


    // Get Enum Values & Encode Array
    public function preManipulateValidatedData($data)
    {
        $schema = $this->getSchema();
        foreach ($data as $key => $datum){
            // Set Enum Columns
            if (isset($schema[$key]['type']) && in_array($schema[$key]['type'], ['enum', 'enum_single']))
            {
                $data[$key] = $this->getEnumColumnValue($key, $datum);
            }

            // Encode If its an Array and as well a column within the table
            if (is_array($datum) && isset($schema[$key]['type'])  && !in_array($schema[$key]['type'], ['file', 'base64file'])){$data[$key] = json_encode($datum);}
        }

        return $data;
    }



}
