<?php

namespace App\Http\Controllers;

use App\Models\Label;
use App\Models\Song;
use App\Models\SongArrangement;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ArrangementController extends Controller
{
    public function store(Request $request, Song $song): RedirectResponse
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
        ]);

        DB::transaction(function () use ($song, $data): void {
            $arrangement = $song->arrangements()->create([
                'name' => $data['name'],
                'is_default' => false,
            ]);

            $defaultArr = $song->arrangements()->where('is_default', true)->first();

            if ($defaultArr === null) {
                return;
            }

            $arrangementLabels = $defaultArr->arrangementLabels()->orderBy('order')->get();

            $rows = $arrangementLabels->values()->map(fn ($al, $index) => [
                'song_arrangement_id' => $arrangement->id,
                'label_id' => $al->label_id,
                'order' => $index + 1,
                'created_at' => now(),
                'updated_at' => now(),
            ])->all();

            if ($rows !== []) {
                $arrangement->arrangementLabels()->insert($rows);
            }
        });

        return back()->with('success', 'Arrangement wurde hinzugefügt.');
    }

    public function clone(Request $request, SongArrangement $arrangement): RedirectResponse
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
        ]);

        DB::transaction(function () use ($arrangement, $data): void {
            $arrangement->loadMissing('arrangementLabels');

            $clone = $arrangement->song->arrangements()->create([
                'name' => $data['name'],
                'is_default' => false,
            ]);

            $this->cloneArrangementLabels($arrangement, $clone);
        });

        return back()->with('success', 'Arrangement wurde geklont.');
    }

    public function update(Request $request, SongArrangement $arrangement): RedirectResponse
    {
        $data = $request->validate([
            'groups' => ['array'],
            'groups.*.label_id' => ['required', 'integer', 'exists:labels,id'],
            'groups.*.order' => ['required', 'integer', 'min:1'],
            'group_colors' => ['sometimes', 'array'],
            'group_colors.*' => ['required', 'string', 'regex:/^#[0-9A-Fa-f]{6}$/'],
        ]);

        $labelIds = collect($data['groups'] ?? [])->pluck('label_id')->values();

        DB::transaction(function () use ($arrangement, $labelIds, $data): void {
            $arrangement->arrangementLabels()->delete();

            $rows = $labelIds
                ->values()
                ->map(fn (int $labelId, int $index) => [
                    'song_arrangement_id' => $arrangement->id,
                    'label_id' => $labelId,
                    'order' => $index + 1,
                    'created_at' => now(),
                    'updated_at' => now(),
                ])
                ->all();

            if ($rows !== []) {
                $arrangement->arrangementLabels()->insert($rows);
            }

            if (! empty($data['group_colors'])) {
                foreach ($data['group_colors'] as $labelId => $color) {
                    Label::whereKey((int) $labelId)->update(['color' => $color]);
                }
            }
        });

        return back()->with('success', 'Arrangement wurde gespeichert.');
    }

    public function destroy(SongArrangement $arrangement): RedirectResponse
    {
        $song = $arrangement->song;

        if ($song->arrangements()->count() <= 1) {
            return back()->with('error', 'Das letzte Arrangement kann nicht gelöscht werden.');
        }

        DB::transaction(function () use ($arrangement, $song): void {
            $deletedWasDefault = $arrangement->is_default;
            $arrangement->delete();

            if ($deletedWasDefault) {
                $song->arrangements()
                    ->orderBy('id')
                    ->limit(1)
                    ->update(['is_default' => true]);
            }
        });

        return back()->with('success', 'Arrangement wurde gelöscht.');
    }

    private function cloneArrangementLabels(?SongArrangement $source, SongArrangement $target): void
    {
        if ($source === null) {
            return;
        }

        $arrangementLabels = $source->arrangementLabels
            ->sortBy('order')
            ->values();

        $rows = $arrangementLabels
            ->map(fn ($arrangementLabel) => [
                'song_arrangement_id' => $target->id,
                'label_id' => $arrangementLabel->label_id,
                'order' => $arrangementLabel->order,
                'created_at' => now(),
                'updated_at' => now(),
            ])
            ->all();

        if ($rows !== []) {
            $target->arrangementLabels()->insert($rows);
        }
    }
}
