<?php

namespace App\Http\Controllers;

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

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,
            ]);

            $groups = $song->groups()->orderBy('order')->get();
            $rows = $groups->map(fn ($group, $index) => [
                'song_arrangement_id' => $arrangement->id,
                'song_group_id' => $group->id,
                'order' => $index + 1,
                'created_at' => now(),
                'updated_at' => now(),
            ])->all();

            if ($rows !== []) {
                $arrangement->arrangementGroups()->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('arrangementGroups');

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

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

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

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

        $groupIds = collect($data['groups'] ?? [])->pluck('song_group_id')->values();
        $uniqueGroupIds = $groupIds->unique()->values();

        $validGroupIds = $arrangement->song->groups()
            ->whereIn('id', $uniqueGroupIds)
            ->pluck('id');

        if ($uniqueGroupIds->count() !== $validGroupIds->count()) {
            throw ValidationException::withMessages([
                'groups' => 'Du kannst nur Gruppen aus diesem Song verwenden.',
            ]);
        }

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

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

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

            if (! empty($data['group_colors'])) {
                foreach ($data['group_colors'] as $groupId => $color) {
                    $arrangement->song->groups()
                        ->whereKey((int) $groupId)
                        ->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 cloneGroups(?SongArrangement $source, SongArrangement $target): void
    {
        if ($source === null) {
            return;
        }

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

        $rows = $groups
            ->map(fn ($arrangementGroup) => [
                'song_arrangement_id' => $target->id,
                'song_group_id' => $arrangementGroup->song_group_id,
                'order' => $arrangementGroup->order,
                'created_at' => now(),
                'updated_at' => now(),
            ])
            ->all();

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