<?php

namespace App\Http\Controllers;

use Illuminate\Support\Arr;
use App\Services\LearningProductService;
use App\Repositories\FilterItemsAssociation;
use App\Http\Resources\LearningProductResource;
use App\Http\Requests\Learning\LearningProductId;
use App\Http\Requests\Learning\LearningProductStore;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;


class LearningProductController extends Controller
{
    private $learningProductService;

    public function __construct(LearningProductService $learningProductService)
    {
        $this->learningProductService = $learningProductService;
        $this->middleware('auth:sanctum', [
            'except' => [
                'getPublished',
            ]
        ]);
    }

    public function index()
    {
        $learningProducts = $this->learningProductService->withTrashedAndChildren([
            'filters',
            'filters.filter_item.filter',
            // 'versions',
            'accreditations',
            'notifications',
        ])->sortDesc();

        return response()->json(
            LearningProductResource::collection($learningProducts),
            201,
        );;
    }

    public function getPublished()
    {
        $withColumnAll = [
            'filters',
            'filters.filter_item.filter',
            'accreditations',
            'accreditations.filters.filter_item',
            'notifications'
        ];

        $learningProductAll = $this->learningProductService->getPublishedWith($withColumnAll)
            ->groupBy('code')
            ->map(function (Collection $groupedLearningProductAll) {
                return $groupedLearningProductAll->last();
            })
            ->sortDesc()
            ->flatten(1);

        return response()->json(
            LearningProductResource::collection($learningProductAll),
            201,
        );
    }

    public function store(LearningProductStore $request)
    {
        try {
            Log::info('Store method called');

            $isSuperAdmin = auth()->user()->hasRole('super_admin');
            $isAdmin = auth()->user()->hasRole('admin');
            $isOperator = auth()->user()->hasRole('operator');

            Log::info('User roles checked', ['isSuperAdmin' => $isSuperAdmin, 'isAdmin' => $isAdmin, 'isOperator' => $isOperator]);

            if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
                return response()->json(['message' => 'You have no rights to do this'], 401);
            }

            // Is it draft with parent_id marked as published?
            $is_draft = isset($request['parent_id']);
            $is_draft_published = $is_draft && $request['published'];
            
            Log::info('Draft status checked', ['is_draft' => $is_draft, 'is_draft_published' => $is_draft_published]);

            $hasCover = isset($request['cover']) && $request->hasFile('cover');
            $hasTile = isset($request['tile']) && $request->hasFile('tile');
            
            Log::info('File status checked', ['hasCover' => $hasCover, 'hasTile' => $hasTile]);

            // Validate and prepare request data
            $request_data = $request->validated();
            if ($hasCover) {
                $request_data = Arr::except($request_data, ['cover']);
            }
            if ($hasTile) {
                $request_data = Arr::except($request_data, ['tile']);
            }

            // Publish without parent_id
            if ($is_draft_published) {
                $request_data['parent_id'] = null;
            }

            $request_data = Arr::except($request_data, ['filtersGrouped', 'synonymsSelected']);
            
            Log::info('Request data prepared', ['request_data' => $request_data]);

            // Save finally the product
            $learning_product = $this->learningProductService->save($request_data);
            
            Log::info('Learning product saved', ['learning_product' => $learning_product]);

            // Get Filter Items passed
            $filter_items = json_decode(html_entity_decode(stripslashes($request['filtersGrouped'])));
            $synonyms_selected = json_decode(html_entity_decode(stripslashes($request['synonymsSelected'])));
            
            Log::info('Filters and synonyms decoded', ['filter_items' => $filter_items, 'synonyms_selected' => $synonyms_selected]);

            if ($synonyms_selected) {
                $learning_product->synonyms()->sync($synonyms_selected);
            }

            $arrayTmp = [];
            if ($filter_items) {
                foreach ($filter_items as $key => $value) {
                    $arrayTmp[] = $value;
                }

                $filter_items = Arr::collapse($arrayTmp);
                $filter_items = Arr::flatten($arrayTmp);

                // Saves filter items associations with this learning product
                $learning_product->filters()->delete();

                foreach ($filter_items as $filter_item_id) {
                    $filter_association = new FilterItemsAssociation();
                    $filter_association->filter_item_id = $filter_item_id;
                    $learning_product->filters()->save($filter_association);
                }
            }

            // if a file was uploaded as cover or tile, add them
            if ($hasCover) {
                $learning_product->addMediaFromRequest('cover')->toMediaCollection('learning_products_covers');
            }
            if ($hasTile) {
                $learning_product->addMediaFromRequest('tile')->toMediaCollection('learning_products_tiles');
            }

            if ($is_draft) {
                // 1st draft of the published product
                $original_product_published = $this->learningProductService->get($request['parent_id']);

                // If no cover has been attached before
                if (!$hasCover && !$learning_product->cover) {
                    $image = $original_product_published->getMedia('learning_products_covers')->first();

                    if ($image) {
                        $learning_product->copyMedia($image->getPath())->toMediaCollection('learning_products_covers');
                    }
                }

                // If no tile has been attached before
                if (!$hasTile && !$learning_product->tile) {
                    $image = $original_product_published->getMedia('learning_products_tiles')->first();

                    if ($image) {
                        $learning_product->copyMedia($image->getPath())->toMediaCollection('learning_products_tiles');
                    }
                }
            }

            // ForceDelete the parent if draft published
            if ($is_draft_published && $learning_product) {
                $this->destroy($request['parent_id'], true);
            }

            Log::info('Learning product processed successfully', ['learning_product' => $learning_product]);

            // Emit Event to update products
            // broadcast(new \App\Events\ProductsCatalogUpdated);

            if ($learning_product) {
                return response()->json(new LearningProductResource($learning_product), 201);
            } else {
                return response()->json(['message' => 'Learning Product not found.'], 404);
            }
        } catch (\Exception $e) {
            Log::error('Error in LearningProductController@store: ' . $e->getMessage(), ['exception' => $e]);
            return response()->json(['message' => 'Internal Server Error'], 500);
        }
    }

    public function show($id)
    {
        $learning_product = $this->learningProductService->getOneWithChildrenAndTrashed($id, [
            'filters',
            'filters.filter_item.filter',
            'versions',
            'accreditations',
            'notifications',
            'synonyms',
        ]);

        return response()->json(new LearningProductResource($learning_product));
    }

    public function countAll()
    {
        return response()->json($this->learningProductService->countAll());
    }

    public function destroy(String $id, $forceDelete = false)
    {
        try {
            Log::info('Destroy method called', ['id' => $id, 'forceDelete' => $forceDelete]);

            $isSuperAdmin = auth()->user()->hasRole('super_admin');
            $isAdmin = auth()->user()->hasRole('admin');
            $isOperator = auth()->user()->hasRole('operator');

            if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
                return response()->json(['message' => 'You have no rights to do this'], 401);
            }

            $learning_product = $this->learningProductService->get($id);

            if (!$learning_product) {
                return response()->json(['message' => 'Learning Product not found.'], 404);
            }

            // Verwijder gerelateerde records in de versions tabel
            \DB::table('versions')->where('learning_product_id', $id)->delete();

            if ($forceDelete) {
                $learning_product->forceDelete();
            } else {
                $learning_product->delete();
            }

            Log::info('Learning product deleted successfully', ['id' => $id]);

            return response()->json(null, 204);
        } catch (\Exception $e) {
            Log::error('Error in LearningProductController@destroy: ' . $e->getMessage(), ['exception' => $e]);
            return response()->json(['message' => 'Internal Server Error'], 500);
        }
    }

    public function clone(LearningProductId $request)
    {
        $isSuperAdmin = auth()->user()->hasRole('super_admin');
        $isAdmin = auth()->user()->hasRole('admin');
        $isOperator = auth()->user()->hasRole('operator');

        if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
            return response()->json(['message' => 'You have no rights to do this'], 401);
        }

        if (!isset($request['product_id']) || !$request['product_id']) {
            return response()->json(['message' => 'Product id missing.'], 400);
        }

        // get original product to clone
        $original_product = $this->learningProductService->getOneWith($request['product_id'], [
            'filters',
            'filters.filter_item.filter',
            'versions',
            'accreditations',
            'notifications',
            'synonyms',
        ]);

        // Return if not published
        if (!$original_product->published) {
            return response()->json([
                'error' => 'You cannot duplicate a draft'
            ], 400);
        }

        // Return already has a draft
        if ($original_product->draft) {
            return response()->json(['message' => 'There is already a draft for this product'], 400);
        }

        // set as draft
        $draft = $original_product->replicate();
        $draft->parent_id = $original_product->id;
        $draft->published = false;

        // clone cover & tiles, finally save
        $cover = $original_product->getMedia('learning_products_covers')->first();
        $tile = $original_product->getMedia('learning_products_tiles')->first();

        if ($cover) {
            $draft
                ->copyMedia($cover->getPath())
                ->toMediaCollection('learning_products_covers');
        }

        if ($tile) {
            $draft
                ->copyMedia($tile->getPath())
                ->toMediaCollection('learning_products_covers');
        }

        $draft->save();

        // TODO: clone accreditations, versions too?

        // Clone Filter Items
        if ($original_product->filters()) {
            $filter_items_ids = $original_product->filters->pluck('filter_item_id');

            foreach ($filter_items_ids as $filter_item_id) {
                $filter_association = new FilterItemsAssociation();
                $filter_association->filter_item_id = $filter_item_id;
                $draft->filters()->save($filter_association);
            }
        }

        // Clone Synonyms
        if ($original_product->synonyms()) {
            $synonyms_ids = $original_product->synonyms->pluck('id');
            $draft->synonyms()->sync($synonyms_ids);
        }

        return response()->json(null, 201);
    }
}
