<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Http\Requests\API\Approval\ActionRequest;
use App\Http\Requests\API\Approval\CopyContainerFileRequest;
use App\Http\Requests\API\Approval\CreateOrUpdateRequest;
use App\Http\Resources\API\ActionByApprovalLogResource;
use App\Http\Resources\API\ApprovalCollection;
use App\Http\Resources\API\ApprovalFlowDetailResource;
use App\Http\Resources\API\FileDownloadResource;
use App\Http\Resources\API\FileSimpleResource;
use App\Http\Resources\API\UserProfileResource;
use App\Models\Action;
use App\Models\Approval;
use App\Models\ApprovalFlow;
use App\Models\Container;
use App\Models\Enums\ApprovalFlowObjectType;
use App\Models\Enums\ApprovalFlowType;
use App\Models\Enums\ApprovalObjectType;
use App\Models\Enums\FileObjectType;
use App\Models\Enums\FolderObjectType;
use App\Models\Enums\ObjectAction;
use App\Models\Enums\ObjectApprovalStatus;
use App\Models\File;
use App\Models\Folder;
use App\Models\Scopes\CompanyScope;
use App\Repositories\ActionRepository;
use App\Repositories\ApprovalRepository;
use App\Services\Approval\ActionService;
use App\Services\Approval\StoreService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use function Symfony\Component\Translation\t;

class ApprovalController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        $pageSize=$request->get('page_size') ?? 10;
        $query = Approval::with(['createdBy']);

        match ($request->get("tab")) {
            'wait_for_me' => $query->allowed(),
            'pr' => $query->where("created_by", Auth::id()),
            'my_approval' => $query->where("action_users", 'like', '%,'.Auth::id().',%'),
            default => $query->allowed(true),
        };

        $approvals = $query->filter($request->all())->orderByDesc("created_at")->paginate($pageSize);
        make_display_id($approvals,$pageSize);
        return new ApprovalCollection($approvals);
    }

    public function publicSearch(Request $request){
        $pageSize=$request->get('page_size') ?? 10;
        $approvals= Approval::filter($request->all())->allowed(true)->orderByDesc("created_at")->paginate($pageSize);
        make_display_id($approvals,$pageSize);
        return new ApprovalCollection($approvals);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(CreateOrUpdateRequest $request, StoreService $service)
    {
        $service->store();

        return $this->created();
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        $approval = Approval::query()
            ->where("id", $id)
            ->allowed(true)
            ->firstOrFail();

        $approvalObjectType = ApprovalObjectType::from($approval->object_type);
        $object = $approvalObjectType
            ->modelBuilder()
            ->findOrFail($approval->object_id);

        $actions = Action::with(['createdBy', 'file'])->where([
            'object_type' => $approvalObjectType->actionObjectType(),
            'object_id' => $object->id,
            'additional_id' => $approval->id,
        ])->orderByDesc("created_at")->get();

        $subObjects = [];
        if ($approvalObjectType == ApprovalObjectType::CONTAINER_FILE && $approval->sub_object_ids) {
            $containerFiles = File::query()->whereIn("id", $approval->sub_object_ids)->get();
            $subObjects = FileDownloadResource::collection($containerFiles);
        }

        return $this->success([
            'data' => [
                'id' => $approval->id,
                'status' => $approval->status,
                'object_type' => $approval->object_type,
                'object_id' => $approval->object_id,
                'object' => [
                    'id' => $object->id,
                    'name' => $object[$approvalObjectType->nameField()],
                ],
                'remark' => $approval->remark,
                'node_level' => $approval->node_level,
                'created_by' => new UserProfileResource($approval->createdBy),
                'approval_flow' => new ApprovalFlowDetailResource($approval->approvalFlow),
                'approval_logs' => ActionByApprovalLogResource::collection($actions),
                'sub_objects' => $subObjects,
                'file_copied' => $approval->file_copied,
                'copy_file_permission' => $approvalObjectType == ApprovalObjectType::CONTAINER_FILE
                    && $approval->last_action_user_id == Auth::id()
                    && $approval->status == ObjectApprovalStatus::APPROVED->value,
            ]
        ]);
    }

    public function action(ActionRequest $request, string $id, ActionService $actionService)
    {
        $approval = Approval::query()
            ->allowed()
            ->whereIn("status", [
                ObjectApprovalStatus::DOING->value,
            ])
            ->find($id);

        throw_validation_if(! $approval, "No authority for approval");

        $actionService->action($approval, $request->status, $request->get("comment"), $request->file("signature_file"));

        return $this->noContent();
    }

    public function detail(Request $request)
    {
        //判断是否已经有审批
        $approvalList = Approval::query()
            ->withoutGlobalScope(CompanyScope::class)
            ->where('object_type', $request->get('object_type'))
            ->where('object_id', $request->get('object_id'))
            ->get();
        $approval = '';
        foreach ($approvalList as $item) {
            if (in_array($request->get('file_id'),$item->sub_object_ids)){
                $approval = $item;
            }
        }
        //Get total approvalFlow
        if ($approval) {
            $approvalFlow = ApprovalFlow::query()->withoutGlobalScope(CompanyScope::class)->find($approval->approval_flow_id);
        }else{
            return $this->success([
                'data' => [],
            ]);
        }

        //获取审批时间
        $action = Action::with(['createdBy', 'file'])->where([
            'object_type' => $request->get('object_type'),
            'object_id' => $request->get('object_id'),
            'additional_id' => $approval->id,
        ])->orderBy("created_at")->get();

        return $this->success([
            'data' => ApprovalRepository::approvalDetail($approvalFlow,ActionByApprovalLogResource::collection($action)),
        ]);
    }
    /**
     * Update the specified resource in storage.
     */
    public function update(CreateOrUpdateRequest $request, string $id)
    {
        $approval = Approval::query()->findOrFail($id);

        ApprovalObjectType::from($approval->object_type)
            ->modelBuilderAllowed($approval->object_id)
            ->findOrFail($approval->object_id);

        $approval->remark = $request->remark;
        $approval->save();

        return $this->noContent();
    }

    /**
     * Remove the specified resource from storage.
     */
    public function cancel(Request $request)
    {
        $mode = $request->get("mode", "approval");
        throw_validation_if(!$request->get("id"), "ID cannot be empty");

        $where = match ($mode) {
            "approval" => ["id" => $request->id],
            "object_type" => ["object_type" => $request->object_type, "object_id" => $request->id],
            default => [],
        };

        throw_validation_if(! $where, "Please enter valid parameters.");

        $approval = Approval::query()
            ->whereIn("status", [
                ObjectApprovalStatus::DOING->value,
            ])
            ->where($where)
            ->first();
        throw_validation_if(! $approval, "The data does not exist or the operation is denied permission.");

        $approvalObjectType = ApprovalObjectType::from($approval->object_type);
        $object = $approvalObjectType->modelBuilderAllowed($approval->object_id)->findOrFail($approval->object_id);

        $approval->status = ObjectApprovalStatus::CANCELED;
        $approval->save();

        ActionRepository::createByApproval($approval, ObjectAction::APPROVED_CANCELED);

        if ($approvalObjectType == ApprovalObjectType::CONTAINER_FILE) {
            File::query()->whereIn("id", $approval->sub_object_ids)->update([
                'approval_status' => ObjectApprovalStatus::WAIT
            ]);
        } else {
            $object->approval_status = ObjectApprovalStatus::CANCELED;
            $object->save();
        }

        return $this->noContent();
    }

    /**
     * @param CopyContainerFileRequest $request
     * @param string $id
     * @return \Illuminate\Http\Response
     */
    public function copyContainerFile(CopyContainerFileRequest $request, string $id)
    {
        $approval = Approval::query()
            ->where("status", ObjectApprovalStatus::APPROVED->value)
            ->where("last_action_user_id", Auth::id())
            ->where("object_type", ApprovalObjectType::CONTAINER_FILE)
            ->find($id);

        throw_validation_if(! $approval, "No authority for approval");

        $targetFolder = Folder::query()
            ->where("object_type", FolderObjectType::CONTAINER)
            ->where("object_id", $approval->object_id)
            ->find($request->get("target_folder_id"));

        throw_validation_if(! $targetFolder, "Target folder does not exist.");

        $files = File::query()->whereIn("id", $approval->sub_object_ids)->get();

        foreach ($files as $file) {
            $fileBuilder = File::query()
                ->where('object_type', FileObjectType::CONTAINER)
                ->where('object_id', $file->object_id)
                ->where("title", $file->title)
                ->where("source", 1)
                ->where("folder_id", $targetFolder->id);

            $version = (clone $fileBuilder)->count();

            (clone $fileBuilder)->update(['is_latest_version' => 0]);

            $file->replicate()->fill([
                'source_file_id' => $file->id,
                'folder_id' => $targetFolder->id,
                'version' => $version + 1,
                'is_latest_version' => 1,
            ])->save();
        }

        $approval->file_copied = true;
        $approval->save();

        return $this->noContent();
    }
}