<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Http\Requests\API\Folder\CreateRequest;
use App\Http\Requests\API\Folder\UpdateRequest;
use App\Http\Resources\API\FileByObjectResource;
use App\Http\Resources\API\FolderDetailResource;
use App\Models\Enums\FolderObjectType;
use App\Models\File;
use App\Models\Folder;
use App\Models\Library;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class FolderController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function tree(string $objectType, string $objectId)
    {
        $folderObjectType = FolderObjectType::from($objectType);

        $folderObjectType->modelBuilderAllowed()->findOrFail($objectId);

        $folders = Folder::query()
            ->where([
                'object_type' => $objectType,
                'object_id' => $objectId,
            ])
            ->when(request("parent_id", 0) > 0, function ($query) {
                return $query->where("path", "like", "%," . \request("parent_id") . ",%")->where("id", "!=", \request("parent_id"));
            })
            ->orderByDesc("sequence")
            ->get([
                'id',
                'name',
                'parent_id'
            ])
            ->each(function ($folders){
                $folders->type='folder';
                $folders->uniId=uniqid();
            });
        return $this->success([
            'data' => make_tree($folders->toArray(), \request("parent_id", 0)),
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(CreateRequest $request)
    {
        $folderObjectType = FolderObjectType::from($request->object_type);

        $object = $folderObjectType->modelBuilderAllowed()->findOrFail($request->object_id);

        $objectWhere = [
            'object_type' => $folderObjectType->value, 'object_id' => $object->id
        ];

        $parentFolder = $request->parent_id > 0
            ? Folder::query()->where($objectWhere)->findOrFail($request->parent_id)
            : null;

        $names = [];
        $updateFolders = [];

        foreach ($request->items as $item) {
            if (! isset($item['name']) || !$item['name']) {
                return $this->badRequest("Folder name cannot be empty");
            }

            if (in_array($item['name'], $names)) {
                return $this->badRequest("Folder names must be unique");
            }
            $names[] = $item['name'];

            $isUpdate = isset($item['id']) && $item['id'];

            $count = Folder::query()
                ->where($objectWhere)
                ->where("parent_id", $request->parent_id)
                ->when($isUpdate, function ($query) use ($item) {
                    return $query->where("id", "!=", $item['id']);
                })
                ->where("name", $item['name'])
                ->count();
            if ($count > 0) {
                return $this->badRequest(sprintf("Folder '%s' must be unique", $item['name']));
            }

            if ($isUpdate) {
                $folder = Folder::query()
                    ->where($objectWhere)
                    ->where("parent_id", $request->parent_id)
                    ->find($item['id']);
                if (! $folder) {
                    return $this->badRequest("Illegal parameters or the file relationship that needs to be updated has changed.");
                }

                $updateFolders[$item['id']] = $folder;
            }
        }

        foreach ($request->items as $item) {
            $isUpdate = isset($item['id']) && $item['id'];
            $data = [
                'name' => $item['name'],
                'sequence' => data_get($item, "sequence", 0),
            ];

            if ($isUpdate) {
                $folder = $updateFolders[$item['id']];
                $folder->fill($data);
                $folder->save();
            } else {
                $folder = Folder::query()->create([
                    'company_id' => Auth::user()->company_id,
                    ...$objectWhere,
                    'parent_id' => $request->parent_id,
                    ...$data
                ]);

                $folder->path = $parentFolder ? $parentFolder?->path . $folder->id . "," : sprintf(",%s,", $folder->id);
                $folder->save();
            }
        }

        return $this->created();
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        $folder = Folder::query()->findOrFail($id);

        return new FolderDetailResource($folder);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(UpdateRequest $request, string $id)
    {
        $folder = Folder::query()->findOrFail($id);

        $folderObjectType = FolderObjectType::from($folder->object_type);

        $object = $folderObjectType->modelBuilderAllowed()->findOrFail($folder->object_id);

        $objectWhere = [
            'object_type' => $folderObjectType->value, 'object_id' => $object->id
        ];

        $parentFolder = Folder::query()->where($objectWhere)->findOrFail($request->parent_id ?? $folder->id);
        if (! $parentFolder) {
            return $this->badRequest("Parent folder does not exist");
        }

        $count = Folder::query()
            ->where($objectWhere)
            ->where("parent_id", $request->parent_id)
            ->where("name", $request->name)
            ->where("id", "!=", $folder->id)
            ->count();
        if ($count > 0) {
            return $this->badRequest(sprintf("Folder '%s' must be unique", $request->name));
        }

        $fields = ['name', 'sequence'];
        if ($parentFolder?->id == $folder->parent_id) {
            $folder->fill($request->only($fields));
            $folder->save();
        } else {
            $path = $parentFolder->path . $folder->id . ",";
            $folderData = [
                ...$request->only($fields),
                'path' => $path,
                'parent_id' => $request->parent_id,
            ];

            $children = Folder::query()
                ->where($objectWhere)
                ->where("id", "!=", $folder->id)
                ->where("path", "like", "%," . $folder->id . ",%")
                ->get();

            foreach ($children as $child) {
                $child->fill([
                    'path' => str_replace($folder->path, $path, $child->path),
                ]);
                $child->save();
            }

            $folder->fill($folderData);
            $folder->save();
        }

        return $this->noContent();
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id)
    {
        $folder = Folder::query()->findOrFail($id);

        $folderObjectType = FolderObjectType::from($folder->object_type);

        $folderObjectType->modelBuilderAllowed()->findOrFail($folder->object_id);

        $children = Folder::query()->where("parent_id", $folder->id)->count();
        if ($children > 0) {
            return $this->badRequest("Subordinate folders or containers exist and are not allowed to be deleted.");
        }

        $folder->delete();

        return $this->noContent();
    }

    public function open(Request $request)
    {
        $folderId = $request->get("id", 0);
        if ($folderId > 0) {
            $folder = Folder::query()->findOrFail($folderId);
            $objectType = $folder->object_type;
            $objectId = $folder->object_id;
        } else {
            $objectType = $request->get("object_type");
            $objectId = $request->get("object_id");
        }

        $folderObjectType = FolderObjectType::from($objectType);

        $folderObjectType->modelBuilderAllowed()->findOrFail($objectId);

        $objectWhere = ['object_type' => $objectType, 'object_id' => $objectId,];
        $folders = Folder::query()
            ->where($objectWhere)
            ->when($folderId, fn($query) => $query->where("parent_id", $folderId))
            ->when(! $folderId, fn($query) => $query->where("parent_id", 0))
            ->get(['id', 'name'])->each(function ($folders)use ($folderId){
                $folderCount=Folder::query()->where('parent_id',$folders->id)->count();
                $filesCount=File::query()->where('folder_id',$folderId>0?$folders->id:$folderId)->where("is_latest_version", 1)->count();
                $folders->itemCount=$folderCount+$filesCount;
            });


        $files = File::query()->where($objectWhere)
            ->where("folder_id", $folderId)
            ->where("is_latest_version", 1)
            ->get();

        return $this->success([
            'data' => [
                'folders' => $folders,
                'files' => FileByObjectResource::collection($files),
            ]
        ]);
    }
}