<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Artwork;
use App\Models\ArtworkAward;
use App\Models\ArtworkMedal;
use App\Models\ArtworkMedalStat;
use App\Services\ArtworkMedalService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

final class ArtworkAwardController extends Controller
{
    public function __construct(
        private readonly ArtworkMedalService $service
    ) {}

    /**
     * POST /api/artworks/{id}/award
     * Award the artwork with a medal.
     */
    public function store(Request $request, int $id): JsonResponse
    {
        $user    = $request->user();
        $artwork = Artwork::findOrFail($id);

        $this->authorize('award', [ArtworkAward::class, $artwork]);

        $data = $request->validate([
            'medal' => ['required', 'string', 'in:gold,silver,bronze'],
        ]);

        $this->service->award($artwork, $user, $data['medal']);

        // Record activity event
        try {
            \App\Models\ActivityEvent::record(
                actorId:    $user->id,
                type:       \App\Models\ActivityEvent::TYPE_AWARD,
                targetType: \App\Models\ActivityEvent::TARGET_ARTWORK,
                targetId:   $artwork->id,
                meta:       ['medal' => $data['medal']],
            );
        } catch (\Throwable) {}

        return response()->json(
            $this->buildPayload($artwork->id, $user->id),
            201
        );
    }

    public function upsert(Request $request, int $id): JsonResponse
    {
        $user = $request->user();
        $artwork = Artwork::findOrFail($id);

        $this->authorize('award', [ArtworkAward::class, $artwork]);

        $data = $request->validate([
            'medal_type' => ['required', 'string', 'in:gold,silver,bronze'],
        ]);

        $existed = ArtworkMedal::query()
            ->where('artwork_id', $artwork->id)
            ->where('user_id', $user->id)
            ->exists();

        $this->service->upsert($artwork, $user, $data['medal_type']);

        return response()->json(
            array_merge($this->buildPayload($artwork->id, $user->id), [
                'message' => $existed ? 'Medal updated.' : 'Medal added.',
            ]),
            $existed ? 200 : 201,
        );
    }

    /**
     * PUT /api/artworks/{id}/award
     * Change an existing award medal.
     */
    public function update(Request $request, int $id): JsonResponse
    {
        $user    = $request->user();
        $artwork = Artwork::findOrFail($id);

        $existingAward = ArtworkMedal::where('artwork_id', $artwork->id)
            ->where('user_id', $user->id)
            ->firstOrFail();

        $this->authorize('change', $existingAward);

        $data = $request->validate([
            'medal' => ['required', 'string', 'in:gold,silver,bronze'],
        ]);

        $this->service->changeMedal($artwork, $user, $data['medal']);

        return response()->json($this->buildPayload($artwork->id, $user->id));
    }

    /**
     * DELETE /api/artworks/{id}/award
     * Remove the user's award for this artwork.
     */
    public function destroy(Request $request, int $id): JsonResponse
    {
        $user    = $request->user();
        $artwork = Artwork::findOrFail($id);

        $existingAward = ArtworkMedal::where('artwork_id', $artwork->id)
            ->where('user_id', $user->id)
            ->firstOrFail();

        $this->authorize('remove', $existingAward);

        $this->service->removeMedal($artwork, $user);

        return response()->json($this->buildPayload($artwork->id, $user->id));
    }

    public function destroyMedal(Request $request, int $id): JsonResponse
    {
        $user = $request->user();
        $artwork = Artwork::findOrFail($id);

        $this->service->removeMedal($artwork, $user);

        return response()->json(array_merge($this->buildPayload($artwork->id, $user->id), [
            'message' => 'Medal removed.',
        ]));
    }

    /**
     * GET /api/artworks/{id}/awards
     * Return award stats + viewer's current award.
     */
    public function show(Request $request, int $id): JsonResponse
    {
        $artwork = Artwork::findOrFail($id);

        return response()->json($this->buildPayload($artwork->id, $request->user()?->id));
    }

    // -------------------------------------------------------------------------
    // All authorization is delegated to ArtworkAwardPolicy via $this->authorize().

    private function buildPayload(int $artworkId, ?int $userId): array
    {
        $stat = ArtworkMedalStat::find($artworkId);

        $userAward = $userId
            ? ArtworkMedal::where('artwork_id', $artworkId)
                ->where('user_id', $userId)
                ->value('medal_type')
            : null;

        $medals = [
            'gold' => (int) ($stat?->gold_count ?? 0),
            'silver' => (int) ($stat?->silver_count ?? 0),
            'bronze' => (int) ($stat?->bronze_count ?? 0),
            'score' => (int) ($stat?->score_total ?? 0),
            'score_7d' => (int) ($stat?->score_7d ?? 0),
            'score_30d' => (int) ($stat?->score_30d ?? 0),
            'last_medaled_at' => $stat?->last_medaled_at?->toIsoString(),
        ];

        return [
            'awards' => $medals,
            'medals' => $medals,
            'viewer_award' => $userAward,
            'current_user_medal' => $userAward,
        ];
    }
}
