<?php

namespace App\Http\Controllers\Api;

use App\Models\Event;
use App\Models\Photo;
use App\Models\User;
use App\Services\EventJoinTokenService;
use App\Support\ApiError;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;

class TenantController extends BaseController
{
    public function __construct(private readonly EventJoinTokenService $joinTokenService) {}

    public function login(Request $request)
    {
        $creds = $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required', 'string'],
        ]);
        if (! Auth::attempt($creds)) {
            return ApiError::response(
                'invalid_credentials',
                'Invalid Credentials',
                'The provided credentials are incorrect.',
                Response::HTTP_UNAUTHORIZED,
                ['email' => $creds['email']]
            );
        }
        /** @var User $user */
        $user = Auth::user();
        // naive token (cache-based), expires in 8 hours
        $token = Str::random(80);
        Cache::put('api_token:'.$token, $user->id, now()->addHours(8));

        return response()->json([
            'token' => $token,
            'user' => [
                'id' => $user->id,
                'name' => $user->name,
                'email' => $user->email,
                'tenant_id' => $user->tenant_id ?? null,
            ],
        ]);
    }

    public function me(Request $request)
    {
        $u = Auth::user();

        return response()->json([
            'id' => $u->id,
            'name' => $u->name,
            'email' => $u->email,
            'tenant_id' => $u->tenant_id ?? null,
        ]);
    }

    public function events()
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $q = Event::query();
        if ($tenantId) {
            $q->where('tenant_id', $tenantId);
        }

        return response()->json(['data' => $q->orderByDesc('created_at')->limit(100)->get(['id', 'name', 'slug', 'date', 'is_active'])]);
    }

    public function showEvent(int $id)
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $ev = Event::findOrFail($id);
        if ($tenantId && $ev->tenant_id !== $tenantId) {
            return $this->forbiddenResponse('events.show', ['event_id' => $ev->id, 'tenant_id' => $tenantId]);
        }

        return response()->json($ev->only(['id', 'name', 'slug', 'date', 'is_active', 'default_locale']));
    }

    public function storeEvent(Request $request)
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'slug' => ['required', 'string', 'max:255'],
            'date' => ['nullable', 'date'],
            'is_active' => ['boolean'],
        ]);
        $ev = new Event;
        $ev->tenant_id = $tenantId ?? $ev->tenant_id;
        $ev->name = ['de' => $data['name'], 'en' => $data['name']];
        $ev->slug = $data['slug'];
        $ev->date = $data['date'] ?? null;
        $ev->is_active = (bool) ($data['is_active'] ?? true);
        $ev->default_locale = 'de';
        $ev->save();

        return response()->json(['id' => $ev->id]);
    }

    public function updateEvent(Request $request, int $id)
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $ev = Event::findOrFail($id);
        if ($tenantId && $ev->tenant_id !== $tenantId) {
            return $this->forbiddenResponse('events.update', ['event_id' => $ev->id, 'tenant_id' => $tenantId]);
        }
        $data = $request->validate([
            'name' => ['nullable', 'string', 'max:255'],
            'slug' => ['nullable', 'string', 'max:255'],
            'date' => ['nullable', 'date'],
            'is_active' => ['nullable', 'boolean'],
        ]);
        if (isset($data['name'])) {
            $ev->name = ['de' => $data['name'], 'en' => $data['name']];
        }
        if (isset($data['slug'])) {
            $ev->slug = $data['slug'];
        }
        if (array_key_exists('date', $data)) {
            $ev->date = $data['date'];
        }
        if (array_key_exists('is_active', $data)) {
            $ev->is_active = (bool) $data['is_active'];
        }
        $ev->save();

        return response()->json(['ok' => true]);
    }

    public function toggleEvent(int $id)
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $ev = Event::findOrFail($id);
        if ($tenantId && $ev->tenant_id !== $tenantId) {
            return $this->forbiddenResponse('events.toggle', ['event_id' => $ev->id, 'tenant_id' => $tenantId]);
        }
        $ev->is_active = ! (bool) $ev->is_active;
        $ev->save();

        return response()->json(['is_active' => (bool) $ev->is_active]);
    }

    public function eventStats(int $id)
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $ev = Event::findOrFail($id);
        if ($tenantId && $ev->tenant_id !== $tenantId) {
            return $this->forbiddenResponse('events.stats', ['event_id' => $ev->id, 'tenant_id' => $tenantId]);
        }
        $total = Photo::where('event_id', $id)->count();
        $featured = Photo::where('event_id', $id)->where('is_featured', 1)->count();
        $likes = Photo::where('event_id', $id)->sum('likes_count');

        return response()->json([
            'total' => (int) $total,
            'featured' => (int) $featured,
            'likes' => (int) $likes,
        ]);
    }

    public function createInvite(Request $request, int $id)
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $ev = Event::findOrFail($id);
        if ($tenantId && $ev->tenant_id !== $tenantId) {
            return $this->forbiddenResponse('events.invite', ['event_id' => $ev->id, 'tenant_id' => $tenantId]);
        }

        $joinToken = $this->joinTokenService->createToken($ev, [
            'created_by' => $u?->id,
        ]);

        return response()->json([
            'link' => url('/e/'.$joinToken->token),
            'legacy_link' => url('/e/'.$ev->slug).'?invite='.$joinToken->token,
            'token' => $joinToken->token,
        ]);
    }

    public function eventPhotos(int $id)
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $ev = Event::findOrFail($id);
        if ($tenantId && $ev->tenant_id !== $tenantId) {
            return $this->forbiddenResponse('events.photos', ['event_id' => $ev->id, 'tenant_id' => $tenantId]);
        }
        $rows = Photo::where('event_id', $id)->orderByDesc('created_at')->limit(100)->get(['id', 'thumbnail_path', 'file_path', 'likes_count', 'is_featured', 'created_at']);

        return response()->json(['data' => $rows]);
    }

    public function featurePhoto(int $photoId)
    {
        $p = Photo::findOrFail($photoId);
        $this->authorizePhoto($p);
        $p->is_featured = 1;
        $p->save();

        return response()->json(['ok' => true]);
    }

    public function unfeaturePhoto(int $photoId)
    {
        $p = Photo::findOrFail($photoId);
        $this->authorizePhoto($p);
        $p->is_featured = 0;
        $p->save();

        return response()->json(['ok' => true]);
    }

    public function deletePhoto(int $photoId)
    {
        $p = Photo::findOrFail($photoId);
        $this->authorizePhoto($p);
        $p->delete();

        return response()->json(['ok' => true]);
    }

    private function forbiddenResponse(string $action, array $meta = []): JsonResponse
    {
        return ApiError::response(
            'forbidden',
            'Forbidden',
            'You are not allowed to perform this action.',
            Response::HTTP_FORBIDDEN,
            array_merge(['action' => $action], $meta)
        );
    }

    protected function authorizePhoto(Photo $p): void
    {
        $u = Auth::user();
        $tenantId = $u->tenant_id ?? null;
        $event = Event::find($p->event_id);
        if ($tenantId && $event && $event->tenant_id !== $tenantId) {
            abort(403);
        }
    }
}
