<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Concerns\ResolvesCurrentOrganization;
use App\Models\Conversation;
use App\Models\Organization;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Collection;
use Illuminate\View\View;

class ConversationController extends Controller
{
    use ResolvesCurrentOrganization;

    public function index(Request $request): View
    {
        $organization = $this->currentOrganization($request);
        abort_if($organization === null, 404);
        abort_unless($this->currentUserCan($request, 'view_inbox'), 403);

        $filter = $request->query('filter', 'open');
        $label = $request->query('label');
        
        $conversations = $this->conversationList($organization, $filter, $label);

        $existingLabels = Conversation::where('organization_id', $organization->id)
            ->whereNotNull('label')
            ->distinct()
            ->pluck('label');

        return view('conversations.index', [
            'organization' => $organization,
            'conversations' => $conversations,
            'existingLabels' => $existingLabels,
        ]);
    }

    public function sidebar(Request $request): Response
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null, 403);
        abort_unless($this->currentUserCan($request, 'view_inbox'), 403);

        $activeConversationId = $request->query('active_id');
        $filter = $request->query('filter', 'open');
        $label = $request->query('label');
        
        $conversations = $this->conversationList($organization, $filter, $label);

        return response()->view('conversations.partials.sidebar-list', [
            'conversations' => $conversations,
            'conversation' => $activeConversationId ? Conversation::find($activeConversationId) : null,
        ]);
    }

    public function show(Request $request, string $id): View
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null, 404);

        $conversation = Conversation::withTrashed()->where('id', $id)->where('organization_id', $organization->id)->firstOrFail();
        abort_unless($this->currentUserCan($request, 'view_inbox'), 403);

        $conversation->load([
            'assignedUser',
            'contact',
            'messages' => fn ($query) => $query->oldest('sent_at')->oldest(),
            'unknownQuestions' => fn ($query) => $query->latest(),
            'callbackRequests' => fn ($query) => $query->latest('requested_at'),
        ]);

        $existingLabels = Conversation::where('organization_id', $organization->id)
            ->whereNotNull('label')
            ->distinct()
            ->pluck('label');

        return view('conversations.show', [
            'conversation' => $conversation,
            'conversations' => $this->conversationList($organization),
            'existingLabels' => $existingLabels,
            'assignableMembers' => $organization->memberships()
                ->with('user')
                ->whereIn('role', ['owner', 'admin', 'supervisor', 'agent'])
                ->orderBy('role')
                ->get(),
            'canAssignConversation' => $this->currentUserCan($request, 'assign_conversations') || $this->currentUserCan($request, 'take_over_handoffs'),
        ]);
    }

    public function updateLabel(Request $request, Conversation $conversation): RedirectResponse
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null && $conversation->organization_id === $organization->id, 404);
        
        $request->validate([
            'label' => 'nullable|string|max:50',
        ]);
        
        $conversation->update(['label' => $request->input('label')]);
        
        return back()->with('status', 'Label updated.');
    }

    public function archive(Request $request, Conversation $conversation): RedirectResponse
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null && $conversation->organization_id === $organization->id, 404);
        
        $conversation->update(['status' => 'archived']);
        
        return back()->with('status', 'Conversation archived.');
    }

    public function unarchive(Request $request, Conversation $conversation): RedirectResponse
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null && $conversation->organization_id === $organization->id, 404);
        
        $conversation->update(['status' => 'open']);
        
        return back()->with('status', 'Conversation unarchived.');
    }

    public function destroy(Request $request, Conversation $conversation): RedirectResponse
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null && $conversation->organization_id === $organization->id, 404);
        
        $conversation->delete();
        
        return redirect()->route('conversations.index')->with('status', 'Conversation moved to trash.');
    }

    public function restore(Request $request, string $id): RedirectResponse
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null, 404);
        
        $conversation = Conversation::onlyTrashed()->where('id', $id)->where('organization_id', $organization->id)->firstOrFail();
        $conversation->restore();
        
        return back()->with('status', 'Conversation restored.');
    }

    public function forceDestroy(Request $request, string $id): RedirectResponse
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null, 404);
        
        $conversation = Conversation::onlyTrashed()->where('id', $id)->where('organization_id', $organization->id)->firstOrFail();
        $conversation->forceDelete();
        
        return redirect()->route('conversations.index', ['filter' => 'trash'])->with('status', 'Conversation permanently deleted.');
    }

    public function bulkAction(Request $request): \Illuminate\Http\JsonResponse
    {
        $organization = $this->currentOrganization($request);
        abort_unless($organization !== null, 404);

        $action = $request->input('action');
        $ids = $request->input('ids', []);

        if (empty($ids)) {
            return response()->json(['success' => false, 'message' => 'No items selected.']);
        }

        $query = Conversation::withTrashed()->whereIn('id', $ids)->where('organization_id', $organization->id);

        switch ($action) {
            case 'archive':
                $query->whereNull('deleted_at')->update(['status' => 'archived']);
                break;
            case 'unarchive':
                $query->whereNull('deleted_at')->update(['status' => 'open']);
                break;
            case 'trash':
                $query->whereNull('deleted_at')->delete();
                break;
            case 'restore':
                $query->onlyTrashed()->restore();
                break;
            case 'forceDestroy':
                $query->onlyTrashed()->forceDelete();
                break;
            default:
                return response()->json(['success' => false, 'message' => 'Invalid action.']);
        }

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

    /**
     * @return Collection<int, Conversation>
     */
    private function conversationList(?Organization $organization, string $filter = 'open', ?string $label = null): Collection
    {
        $query = $organization?->conversations()
            ->with(['contact', 'assignedUser', 'latestMessage'])
            ->withCount('messages');
            
        if ($filter === 'trash') {
            $query->onlyTrashed();
        } elseif ($filter === 'archived') {
            $query->where('status', 'archived');
        } else {
            $query->where('status', '!=', 'archived');
        }
        
        if ($label !== null) {
            $query->where('label', $label);
        }

        return $query->orderByDesc('last_message_at')
            ->orderByDesc('created_at')
            ->get() ?? collect();
    }
}
