<?php

namespace App\Http\Controllers\Api\V1;

use App\Actions\CreateChannelAction;
use App\Http\Requests\StorePlatformChannelRequest;
use App\Http\Resources\PlatformChannelResource;
use App\Models\PlatformAccount;
use App\Models\PlatformChannel;
use App\Models\PlatformInstance;
use App\Services\Platform\CommunityDirectory;
use Exception;
use Illuminate\Database\UniqueConstraintViolationException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use RuntimeException;

class PlatformChannelsController extends BaseController
{
    /**
     * Display a listing of platform channels
     */
    public function index(): JsonResponse
    {
        $channels = PlatformChannel::with(['platformInstance', 'platformAccounts'])
            ->orderBy('is_active', 'desc')
            ->orderBy('name')
            ->get();

        return $this->sendResponse(
            PlatformChannelResource::collection($channels),
            'Platform channels retrieved successfully.'
        );
    }

    /**
     * Store a newly created platform channel
     */
    public function store(StorePlatformChannelRequest $request, CreateChannelAction $createChannelAction): JsonResponse
    {
        try {
            $validated = $request->validated();

            $instance = PlatformInstance::query()->findOrFail((int) $validated['platform_instance_id']);
            $name = app(CommunityDirectory::class)->name($instance, (int) $validated['channel_id']);

            $channel = $createChannelAction->execute(
                $name,
                (int) $validated['channel_id'],
                $validated['platform_instance_id'],
                $validated['language_id'] ?? null,
                $validated['description'] ?? null,
            );

            return $this->sendResponse(
                new PlatformChannelResource($channel->load(['platformInstance', 'platformAccounts'])),
                'Platform channel created successfully and linked to platform account!',
                201
            );
        } catch (UniqueConstraintViolationException $e) {
            // The (platform_instance_id, channel_id) unique index is the last line of
            // defence if a duplicate slips past request validation — surface it as a
            // validation error rather than leaking the driver's SQL message in a 500.
            return $this->sendError('A channel with this name already exists for this instance.', [], 422);
        } catch (RuntimeException $e) {
            return $this->sendError($e->getMessage(), [], 422);
        } catch (Exception $e) {
            return $this->sendError('Failed to create platform channel: '.$e->getMessage(), [], 500);
        }
    }

    /**
     * Display the specified platform channel
     */
    public function show(PlatformChannel $platformChannel): JsonResponse
    {
        return $this->sendResponse(
            new PlatformChannelResource($platformChannel->load('platformInstance')),
            'Platform channel retrieved successfully.'
        );
    }

    /**
     * Update the specified platform channel
     */
    public function update(Request $request, PlatformChannel $platformChannel): JsonResponse
    {
        try {
            $validated = $request->validate([
                'name' => 'required|string|max:255',
                'display_name' => 'nullable|string|max:255',
                'description' => 'nullable|string',
                'is_active' => 'boolean',
            ]);

            $platformChannel->update($validated);

            return $this->sendResponse(
                new PlatformChannelResource($platformChannel->fresh(['platformInstance'])),
                'Platform channel updated successfully!'
            );
        } catch (ValidationException $e) {
            return $this->sendValidationError($e->errors());
        } catch (Exception $e) {
            return $this->sendError('Failed to update platform channel: '.$e->getMessage(), [], 500);
        }
    }

    /**
     * Remove the specified platform channel
     */
    public function destroy(PlatformChannel $platformChannel): JsonResponse
    {
        try {
            $platformChannel->delete();

            return $this->sendResponse(
                null,
                'Platform channel deleted successfully!'
            );
        } catch (Exception $e) {
            return $this->sendError('Failed to delete platform channel: '.$e->getMessage(), [], 500);
        }
    }

    /**
     * Toggle platform channel active status
     */
    public function toggle(PlatformChannel $channel): JsonResponse
    {
        try {
            $newStatus = ! $channel->is_active;
            $channel->update(['is_active' => $newStatus]);

            $status = $newStatus ? 'activated' : 'deactivated';

            return $this->sendResponse(
                new PlatformChannelResource($channel->fresh(['platformInstance', 'platformAccounts'])),
                "Platform channel {$status} successfully!"
            );
        } catch (Exception $e) {
            return $this->sendError('Failed to toggle platform channel status: '.$e->getMessage(), [], 500);
        }
    }

    /**
     * Attach a platform account to a channel
     */
    public function attachAccount(PlatformChannel $channel, Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'platform_account_id' => 'required|exists:platform_accounts,id',
                'is_active' => 'boolean',
                'priority' => 'nullable|integer|min:1|max:100',
            ]);

            /** @var PlatformAccount $platformAccount */
            $platformAccount = PlatformAccount::findOrFail($validated['platform_account_id']);

            // Check if account is already attached
            if ($channel->platformAccounts()->where('platform_account_id', $platformAccount->id)->exists()) {
                return $this->sendError('Platform account is already attached to this channel.', [], 422);
            }

            $channel->platformAccounts()->attach($platformAccount->id, [
                'is_active' => $validated['is_active'] ?? true,
                'priority' => $validated['priority'] ?? 1,
                'created_at' => now(),
                'updated_at' => now(),
            ]);

            return $this->sendResponse(
                new PlatformChannelResource($channel->fresh(['platformInstance', 'platformAccounts'])),
                'Platform account attached to channel successfully!'
            );
        } catch (ValidationException $e) {
            return $this->sendValidationError($e->errors());
        } catch (Exception $e) {
            return $this->sendError('Failed to attach platform account: '.$e->getMessage(), [], 500);
        }
    }

    /**
     * Detach a platform account from a channel
     */
    public function detachAccount(PlatformChannel $channel, PlatformAccount $account): JsonResponse
    {
        try {
            if (! $channel->platformAccounts()->where('platform_account_id', $account->id)->exists()) {
                return $this->sendError('Platform account is not attached to this channel.', [], 422);
            }

            $channel->platformAccounts()->detach($account->id);

            return $this->sendResponse(
                new PlatformChannelResource($channel->fresh(['platformInstance', 'platformAccounts'])),
                'Platform account detached from channel successfully!'
            );
        } catch (Exception $e) {
            return $this->sendError('Failed to detach platform account: '.$e->getMessage(), [], 500);
        }
    }

    /**
     * Update platform account-channel relationship settings
     */
    public function updateAccountRelation(PlatformChannel $channel, PlatformAccount $account, Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'is_active' => 'boolean',
                'priority' => 'nullable|integer|min:1|max:100',
            ]);

            if (! $channel->platformAccounts()->where('platform_account_id', $account->id)->exists()) {
                return $this->sendError('Platform account is not attached to this channel.', [], 422);
            }

            $channel->platformAccounts()->updateExistingPivot($account->id, [
                'is_active' => $validated['is_active'] ?? true,
                'priority' => $validated['priority'] ?? 1,
                'updated_at' => now(),
            ]);

            return $this->sendResponse(
                new PlatformChannelResource($channel->fresh(['platformInstance', 'platformAccounts'])),
                'Platform account-channel relationship updated successfully!'
            );
        } catch (ValidationException $e) {
            return $this->sendValidationError($e->errors());
        } catch (Exception $e) {
            return $this->sendError('Failed to update platform account relationship: '.$e->getMessage(), [], 500);
        }
    }
}
