<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\MessengerChannelResource;
use App\Models\MessengerChannel;
use App\Support\CrmModuleManager;
use App\Support\MessengerAccess;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class MessengerChannelController extends Controller
{
    public function __construct()
    {
        $this->authorizeResource(MessengerChannel::class, 'channel');
    }

    public function index(Request $request)
    {
        $search = trim((string) $request->input('q', ''));
        $provider = trim((string) $request->input('provider', ''));
        if ($provider !== '') {
            $provider = MessengerAccess::normalizeProvider($provider);
        }
        $status = trim((string) $request->input('status', ''));

        $channels = MessengerChannel::query()
            ->withCount('conversations')
            ->when($search !== '', function ($query) use ($search): void {
                $query->where(function ($sub) use ($search): void {
                    $sub->where('name', 'like', "%{$search}%")
                        ->orWhere('handle', 'like', "%{$search}%")
                        ->orWhere('external_id', 'like', "%{$search}%");
                });
            })
            ->when($provider !== '', fn ($query) => $query->where('provider', $provider))
            ->when($status !== '', fn ($query) => $query->where('status', $status))
            ->orderBy('name')
            ->paginate(30)
            ->withQueryString();

        return MessengerChannelResource::collection($channels);
    }

    public function store(Request $request, CrmModuleManager $moduleManager): MessengerChannelResource
    {
        $providerValues = array_keys(MessengerAccess::providerOptions());
        $provider = MessengerAccess::normalizeProvider($request->input('provider', ''));
        $validated = $request->validate([
            'provider' => ['required', Rule::in($providerValues)],
            'external_id' => [
                'nullable',
                'string',
                'max:255',
                Rule::unique('messenger_channels', 'external_id')->where(fn ($query) => $query->where('provider', $provider)),
            ],
            'name' => ['required', 'string', 'max:255'],
            'handle' => ['nullable', 'string', 'max:120'],
            'status' => ['required', Rule::in(['active', 'disabled'])],
            'is_default' => ['nullable', 'boolean'],
            'meta' => ['nullable', 'array'],
        ]);

        $payload = [
            'provider' => MessengerAccess::normalizeProvider($validated['provider']),
            'external_id' => $this->nullableText($validated['external_id'] ?? null),
            'name' => trim((string) $validated['name']),
            'handle' => $this->nullableText($validated['handle'] ?? null),
            'status' => (string) $validated['status'],
            'is_default' => (bool) ($validated['is_default'] ?? false),
            'meta' => $validated['meta'] ?? null,
        ];

        $payload = $moduleManager->applyPayloadHooks('messengers.channels.store', $payload, [
            'hook' => 'messengers.channels.store',
            'user_id' => $request->user()->id,
            'source' => 'api',
        ], array_keys($payload));

        if ($payload['is_default']) {
            MessengerChannel::query()->update(['is_default' => false]);
        }

        $channel = MessengerChannel::query()->create($payload);

        return MessengerChannelResource::make($channel->loadCount('conversations'));
    }

    public function show(MessengerChannel $channel): MessengerChannelResource
    {
        return MessengerChannelResource::make($channel->loadCount('conversations'));
    }

    public function update(Request $request, MessengerChannel $channel, CrmModuleManager $moduleManager): MessengerChannelResource
    {
        $providerValues = array_keys(MessengerAccess::providerOptions());
        $provider = MessengerAccess::normalizeProvider($request->input('provider', $channel->provider));
        $validated = $request->validate([
            'provider' => ['required', Rule::in($providerValues)],
            'external_id' => [
                'nullable',
                'string',
                'max:255',
                Rule::unique('messenger_channels', 'external_id')
                    ->where(fn ($query) => $query->where('provider', $provider))
                    ->ignore($channel->id),
            ],
            'name' => ['required', 'string', 'max:255'],
            'handle' => ['nullable', 'string', 'max:120'],
            'status' => ['required', Rule::in(['active', 'disabled'])],
            'is_default' => ['nullable', 'boolean'],
            'meta' => ['nullable', 'array'],
        ]);

        $payload = [
            'provider' => MessengerAccess::normalizeProvider($validated['provider']),
            'external_id' => $this->nullableText($validated['external_id'] ?? null),
            'name' => trim((string) $validated['name']),
            'handle' => $this->nullableText($validated['handle'] ?? null),
            'status' => (string) $validated['status'],
            'is_default' => (bool) ($validated['is_default'] ?? false),
            'meta' => $validated['meta'] ?? null,
        ];

        $payload = $moduleManager->applyPayloadHooks('messengers.channels.update', $payload, [
            'hook' => 'messengers.channels.update',
            'user_id' => $request->user()->id,
            'channel_id' => $channel->id,
            'source' => 'api',
        ], array_keys($payload));

        if ($payload['is_default']) {
            MessengerChannel::query()->whereKeyNot($channel->id)->update(['is_default' => false]);
        }

        $channel->update($payload);

        return MessengerChannelResource::make($channel->loadCount('conversations'));
    }

    public function destroy(MessengerChannel $channel)
    {
        $channel->delete();

        return response()->noContent();
    }

    private function nullableText(mixed $value): ?string
    {
        $value = trim((string) $value);

        return $value === '' ? null : $value;
    }
}
