<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\V1;

use App\Domain\Account\Models\Account;
use App\Domain\Email\Models\EmailAccount;
use App\Domain\Email\Models\EmailForwarder;
use App\Http\Controllers\Controller;
use App\Http\Resources\Api\V1\EmailAccountResource;
use App\Http\Resources\Api\V1\EmailForwarderResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

/**
 * Email accounts + forwarders resource.
 *
 * Note: Bu controller hem email-accounts hem de email-forwarders rotalarına
 * hizmet eder. Route model binding route parametresine göre çalışır.
 */
class EmailApiController extends Controller
{
    // ─── Email Accounts ───────────────────────────────────────────────────

    public function index(Request $request): JsonResponse
    {
        $this->requireAbility($request, 'email:read');

        // Forwarder listesi mi, email account listesi mi?
        if ($request->routeIs('*.email-forwarders.*')) {
            return $this->forwardersIndex($request);
        }

        $query = EmailAccount::query();
        $user = $request->user();

        if (! $user->hasRole('admin')) {
            $accountId = Account::where('owner_user_id', $user->id)->value('id');
            $query->where('account_id', $accountId);
        } elseif ($accountId = $request->integer('account_id')) {
            $query->where('account_id', $accountId);
        }

        $emails = $query->latest()->paginate($request->integer('per_page', 25));

        return EmailAccountResource::collection($emails)->response();
    }

    public function show(Request $request, EmailAccount $emailAccount): JsonResponse
    {
        $this->requireAbility($request, 'email:read');
        $this->authorizeScope($request, $emailAccount->account_id);

        return (new EmailAccountResource($emailAccount))->response();
    }

    public function store(Request $request): JsonResponse
    {
        $this->requireAbility($request, 'email:write');

        // Forwarder mı?
        if ($request->routeIs('*.email-forwarders.*')) {
            return $this->forwardersStore($request);
        }

        $validated = $request->validate([
            'account_id' => ['required', 'exists:accounts,id'],
            'local' => ['required', 'string', 'max:64', 'regex:/^[a-z0-9._%+\-]+$/i'],
            'domain' => ['required', 'string', 'max:255'],
            'password' => ['required', 'string', 'min:8'],
            'quota_mb' => ['sometimes', 'integer', 'min:-1'],
        ]);

        $this->authorizeScope($request, (int) $validated['account_id']);

        $email = EmailAccount::create([
            'account_id' => $validated['account_id'],
            'local' => strtolower($validated['local']),
            'domain' => strtolower($validated['domain']),
            'password_hash' => bcrypt($validated['password']),
            'quota_mb' => $validated['quota_mb'] ?? 1024,
            'status' => 'active',
        ]);

        return (new EmailAccountResource($email))->response()->setStatusCode(201);
    }

    public function update(Request $request, EmailAccount $emailAccount): JsonResponse
    {
        $this->requireAbility($request, 'email:write');
        $this->authorizeScope($request, $emailAccount->account_id);

        $validated = $request->validate([
            'quota_mb' => ['sometimes', 'integer', 'min:-1'],
            'password' => ['sometimes', 'string', 'min:8'],
        ]);

        if (isset($validated['password'])) {
            $validated['password_hash'] = bcrypt($validated['password']);
            unset($validated['password']);
        }

        $emailAccount->update($validated);

        return (new EmailAccountResource($emailAccount->fresh()))->response();
    }

    public function destroy(Request $request, EmailAccount|EmailForwarder $emailAccount): JsonResponse
    {
        $this->requireAbility($request, 'email:write');

        if ($emailAccount instanceof EmailForwarder) {
            return $this->forwardersDestroy($request, $emailAccount);
        }

        $this->authorizeScope($request, $emailAccount->account_id);
        $emailAccount->delete();

        return response()->json(['data' => ['message' => 'E-posta hesabı silindi.']]);
    }

    // ─── Forwarders ───────────────────────────────────────────────────────

    private function forwardersIndex(Request $request): JsonResponse
    {
        $query = EmailForwarder::query();
        $user = $request->user();

        if (! $user->hasRole('admin')) {
            $accountId = Account::where('owner_user_id', $user->id)->value('id');
            $query->where('account_id', $accountId);
        } elseif ($accountId = $request->integer('account_id')) {
            $query->where('account_id', $accountId);
        }

        return EmailForwarderResource::collection($query->latest()->paginate(25))->response();
    }

    private function forwardersStore(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'account_id' => ['required', 'exists:accounts,id'],
            'source' => ['required', 'email'],
            'destinations' => ['required', 'array', 'min:1'],
            'destinations.*' => ['email'],
            'keep_local_copy' => ['sometimes', 'boolean'],
        ]);

        $this->authorizeScope($request, (int) $validated['account_id']);

        $forwarder = EmailForwarder::create([
            'account_id' => $validated['account_id'],
            'source' => strtolower($validated['source']),
            'destinations' => $validated['destinations'],
            'keep_local_copy' => $validated['keep_local_copy'] ?? false,
            'is_active' => true,
        ]);

        return (new EmailForwarderResource($forwarder))->response()->setStatusCode(201);
    }

    private function forwardersDestroy(Request $request, EmailForwarder $forwarder): JsonResponse
    {
        $this->authorizeScope($request, $forwarder->account_id);
        $forwarder->delete();

        return response()->json(['data' => ['message' => 'Yönlendirici silindi.']]);
    }

    // ─── Helpers ─────────────────────────────────────────────────────────

    private function requireAbility(Request $request, string $ability): void
    {
        $token = $request->user()?->currentAccessToken();
        if ($token && ! in_array('*', $token->abilities, true) && ! in_array($ability, $token->abilities, true)) {
            abort(403, "Token için '{$ability}' yetkisi gerekli.");
        }
    }

    private function authorizeScope(Request $request, int $accountId): void
    {
        $user = $request->user();
        if ($user->hasRole('admin')) {
            return;
        }
        $ownAccountId = Account::where('owner_user_id', $user->id)->value('id');
        if ($ownAccountId !== $accountId) {
            abort(403, 'Bu kaynağa erişim yetkiniz yok.');
        }
    }
}
