<?php

namespace App\Services;

use App\Enums\FeatureEnum;
use App\Exceptions\ApiHttpException;
use App\Models\Project;
use App\Models\ProjectImage;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\Drivers\Imagick\Driver;
use Intervention\Image\ImageManager;
use Throwable;

class ProjectsService
{
    /**
     * Retrieves all projects for the authenticated account (user)
     *
     * @param User $user
     * @return Project|null
     */
    public function getProjects(User $user)
    {
        $profileId = $user->accountMember?->account?->profile?->id;
        $projects = Project::where('company_profile_id', $profileId)
            ->orderBy('created_at', 'desc')
            ->get();

        return $projects;
    }

    /**
     * Retrieves a specific project by ID
     *
     * @param User $user
     * @param int $projectId
     * @return Project|null
     */

    public function getProject(User $user, int $projectId)
    {
        $profileId = $user->accountMember?->account?->profile?->id;
        $project = Project::where('company_profile_id', $profileId)
            ->where('id', $projectId)
            ->with('images')
            ->first();

        return $project;
    }

    /**
     * Creates a Project
     *
     * @param User $user
     * @param array $projectData
     * @return Project
     */
    public function createProject(User $user, Array $projectData)
    {
        if (!$user->hasFeature(FeatureEnum::FULL_DASHBOARD, true)) {
            throw new ApiHttpException(403, trans('frontend.exception_no_permission'));
        }

        $images = $projectData['images'] ?? null;

        DB::beginTransaction();
        try {
            $profile = $user->accountMember?->account?->profile;
            if (!$profile) {
                throw new ApiHttpException(404, trans('frontend.exception_profile_not_found'));
            }

            $project = new Project();
            $project->companyProfile()->associate($profile);
            $project->user()->associate($user);
            $project->name = $projectData['name'];
            $project->content = $projectData['content'];
            $project->project_date = $projectData['projectDate'];
            $project->save();

            if (!empty($images)) {
                $projectImagePath = config('path.internal.project_images');

                if (!Storage::exists($projectImagePath)) {
                    Storage::makeDirectory($projectImagePath);
                }

                foreach ($images as $image) {
                    $this->_saveProjectImages($projectImagePath, $project, $image['file'], null, $image['position'] ?? null);
                }
            }

            DB::commit();
            return $project;
        } catch (Throwable $e) {
            DB::rollback();
            throw $e;
        }
    }

    /**
     * Updates a Project
     *
     * @param User $user
     * @param array $projectData
     * @param int $projectId
     * @return Project
     */
    public function updateProject(User $user, array $projectData, int $projectId)
    {
        if (!$user->hasFeature(FeatureEnum::FULL_DASHBOARD, true)) {
            throw new ApiHttpException(403, trans('frontend.exception_no_permission'));
        }

        $profileId = $user->accountMember?->account?->profile?->id;
        $project = Project::where('company_profile_id', $profileId)->where('id', $projectId)->first();

        if (!$project) {
            throw new ApiHttpException(404, trans('frontend.exception_project_not_found'));
        }

        DB::beginTransaction();
        try {
            $project->name = $projectData['name'];
            $project->project_date = $projectData['projectDate'];

            if (array_key_exists('content', $projectData)) {
                $project->content = $projectData['content'];
            }

            $project->save();

            if (array_key_exists('images', $projectData)) {
                $images = $projectData['images'];

                $projectImagePath = config('path.internal.project_images');

                if (!Storage::exists($projectImagePath)) {
                    Storage::makeDirectory($projectImagePath);
                }

                foreach ($images as $img) {
                    if (isset($img['id']) && isset($img['deleted']) && $img['deleted']) {
                        $existingImage = ProjectImage::where('id', $img['id'])->first();

                        if ($existingImage) {
                            $imagePath = "{$projectImagePath}/{$existingImage->image}";

                            if (Storage::exists($imagePath)) {
                                Storage::delete($imagePath);
                            }

                            $existingImage->delete();
                        }
                    } elseif (isset($img['id']) && isset($img['position'])) {
                        $existingImage = ProjectImage::where('id', $img['id'])->first();
                        if ($existingImage) {
                            $existingImage->position = $img['position'];
                            $existingImage->save();
                        }
                    } elseif (isset($img['file']) && !isset($img['id'])) {
                        $this->_saveProjectImages($projectImagePath, $project, $img['file'], null, $img['position'] ?? null);
                    }
                }
            }

            DB::commit();
            $project->refresh();
            return $project;
        } catch (Throwable $e) {
            DB::rollback();
            throw $e;
        }
    }

    /**
     * Deletes a project
     *
     * @param User $user
     * @param int $projectId
     * @return Project
     */
    public function deleteProject(User $user, int $projectId)
    {
        if (!$user->hasFeature(FeatureEnum::FULL_DASHBOARD, true)) {
            throw new ApiHttpException(403, trans('frontend.exception_no_permission'));
        }

        $profileId = $user->accountMember?->account?->profile?->id;
        $project = Project::where('company_profile_id', $profileId)
            ->where('id', $projectId)
            ->with('images')
            ->first();

        if (!$project) {
            throw new ApiHttpException(404, trans('frontend.exception_project_not_found'));
        }

        $projectImagePath = config('path.internal.project_images');

        foreach ($project->images as $image) {
            $imagePath = "{$projectImagePath}/{$image->image}";
            if (Storage::exists($imagePath)) {
                Storage::delete($imagePath);
            }
        }

        $project->delete();

        return $project;
    }

    public function _saveProjectImages($projectImagePath, $project, $image, $existingImage = null, $position = null)
    {
        $imageName = Str::random() . '.' . $image->extension();
        $manager = new ImageManager(Driver::class);
        $img = $manager->read($image);

        $img->save(Storage::path("{$projectImagePath}/{$imageName}"), 90);

        $projectImage = $existingImage ?? new ProjectImage();
        $projectImage->project_id = $project->id;
        $projectImage->image = $imageName;
        $projectImage->image_original = $image->getClientOriginalName();
        $projectImage->image_size = $image->getSize();
        $projectImage->width = $img->width();
        $projectImage->height = $img->height();
        $projectImage->position = $position;
        $projectImage->save();
    }
}
