<?php

namespace App\Http\Controllers\Api\Mobile;

use App\Exceptions\PlanLimitReachedException;
use App\Http\Controllers\Controller;
use App\Models\EmailAccount;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Email\EmailSendService;
use App\Services\PlanLimitService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

/**
 * Mobile Team Members endpoints.
 *
 * Mirrors the web Settings → Team tab — list members, invite by email,
 * change member role, remove member, list / cancel / resend invites.
 *
 * Role hierarchy: owner > admin > agent > viewer. Only owners can change
 * roles; owners + admins can invite and remove non-owner members. Mirrors
 * TeamManager Livewire authorisation rules exactly.
 */
class TeamController extends Controller
{
    /**
     * GET /api/v1/mobile/team
     */
    public function index(Request $request): JsonResponse
    {
        $user = $request->user();
        $workspace = $user->active_workspace_id
            ? Workspace::find($user->active_workspace_id)
            : null;

        if (!$workspace) {
            return response()->json(['message' => 'No active workspace.'], 422);
        }

        $members = DB::table('workspace_members as wm')
            ->join('users as u', 'u.id', '=', 'wm.user_id')
            ->where('wm.workspace_id', $workspace->id)
            ->orderByRaw("FIELD(wm.role, 'owner', 'admin', 'agent', 'viewer')")
            ->orderBy('u.name')
            ->get(['u.id', 'u.uuid', 'u.name', 'u.email', 'u.avatar_path', 'wm.role', 'wm.status', 'wm.last_active_at']);

        $invites = DB::table('workspace_invites')
            ->where('workspace_id', $workspace->id)
            ->whereIn('status', ['pending', 'expired'])
            ->orderByDesc('created_at')
            ->get(['id', 'email', 'role', 'status', 'expires_at', 'created_at']);

        $myRole = $user->workspaceRole($workspace->id);

        return response()->json([
            'workspace' => [
                'id'   => $workspace->id,
                'name' => $workspace->name,
            ],
            'capabilities' => [
                'can_invite'      => in_array($myRole, ['owner', 'admin'], true),
                'can_change_role' => $myRole === 'owner',
                'can_remove'      => in_array($myRole, ['owner', 'admin'], true),
                'my_role'         => $myRole,
            ],
            'members' => $members->map(function ($m) use ($user) {
                return [
                    'id'            => (int) $m->id,
                    'uuid'          => $m->uuid,
                    'name'          => $m->name,
                    'email'         => $m->email,
                    'avatar_url'    => $m->avatar_path ? asset('storage/' . $m->avatar_path) : null,
                    'initials'      => $this->initials($m->name ?: $m->email ?: '?'),
                    'role'          => $m->role,
                    'role_label'    => ucfirst($m->role),
                    'status'        => $m->status,
                    'is_online'     => $m->status === 'online'
                        || ($m->last_active_at && \Carbon\Carbon::parse($m->last_active_at)->gt(now()->subMinutes(5))),
                    'is_self'       => (int) $m->id === $user->id,
                    'last_active_at' => $m->last_active_at,
                ];
            })->values()->all(),
            'invites' => $invites->map(fn ($i) => [
                'id'         => (int) $i->id,
                'email'      => $i->email,
                'role'       => $i->role,
                'role_label' => ucfirst($i->role),
                'status'     => $i->status,
                'expires_at' => $i->expires_at,
                'is_expired' => $i->expires_at && \Carbon\Carbon::parse($i->expires_at)->lt(now()),
                'created_at' => $i->created_at,
            ])->values()->all(),
            'available_roles' => [
                ['key' => 'admin',  'label' => 'Admin',  'description' => 'Manage workspace + members'],
                ['key' => 'agent',  'label' => 'Agent',  'description' => 'Handle conversations + contacts'],
                ['key' => 'viewer', 'label' => 'Viewer', 'description' => 'Read-only access'],
            ],
        ]);
    }

    /**
     * POST /api/v1/mobile/team/invites
     * Invite a new member by email.
     */
    public function invite(Request $request): JsonResponse
    {
        $user = $request->user();
        $workspace = $user->active_workspace_id
            ? Workspace::find($user->active_workspace_id)
            : null;
        if (!$workspace) {
            return response()->json(['message' => 'No active workspace.'], 422);
        }

        $myRole = $user->workspaceRole($workspace->id);
        if (!in_array($myRole, ['owner', 'admin'], true)) {
            return response()->json(['message' => 'Only owners and admins can invite team members.'], 403);
        }

        $validator = Validator::make($request->all(), [
            'email' => ['required', 'email', 'max:255'],
            'role'  => ['required', 'string', 'in:admin,agent,viewer'],
        ]);
        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()], 422);
        }

        $email = (string) $request->input('email');
        $role  = (string) $request->input('role');

        // Plan limit
        try {
            app(PlanLimitService::class)->assertCanCreate($workspace, 'team_members');
        } catch (PlanLimitReachedException $e) {
            return response()->json(['message' => $e->getMessage()], 422);
        }

        // Already a member?
        $existingUser = User::where('email', $email)->first();
        if ($existingUser && $workspace->members()->where('users.id', $existingUser->id)->exists()) {
            return response()->json([
                'message' => 'This user is already a workspace member.',
                'errors'  => ['email' => ['Already a member.']],
            ], 422);
        }

        // Live pending invite?
        $livePending = DB::table('workspace_invites')
            ->where('workspace_id', $workspace->id)
            ->where('email', $email)
            ->where('status', 'pending')
            ->where('expires_at', '>', now())
            ->exists();
        if ($livePending) {
            return response()->json([
                'message' => 'An invitation has already been sent to this email.',
                'errors'  => ['email' => ['Already invited.']],
            ], 422);
        }

        // Purge stale rows so the unique (workspace_id, email) index is free
        DB::table('workspace_invites')
            ->where('workspace_id', $workspace->id)
            ->where('email', $email)
            ->where(function ($q) {
                $q->where('status', '!=', 'pending')->orWhere('expires_at', '<=', now());
            })
            ->delete();

        $token = Str::random(64);
        $inserted = DB::table('workspace_invites')->insertOrIgnore([
            'workspace_id' => $workspace->id,
            'email'        => $email,
            'role'         => $role,
            'token'        => $token,
            'invited_by'   => $user->id,
            'status'       => 'pending',
            'expires_at'   => now()->addDays(7),
            'created_at'   => now(),
            'updated_at'   => now(),
        ]);

        if (!$inserted) {
            return response()->json([
                'message' => 'An invitation has already been sent to this email.',
                'errors'  => ['email' => ['Already invited.']],
            ], 422);
        }

        $this->sendInviteEmail($workspace, $email, $token);

        $row = DB::table('workspace_invites')
            ->where('workspace_id', $workspace->id)
            ->where('email', $email)
            ->where('token', $token)
            ->first();

        return response()->json([
            'message' => "Invitation sent to {$email}.",
            'invite'  => [
                'id'         => (int) $row->id,
                'email'      => $row->email,
                'role'       => $row->role,
                'status'     => $row->status,
                'expires_at' => $row->expires_at,
                'created_at' => $row->created_at,
            ],
        ], 201);
    }

    /**
     * POST /api/v1/mobile/team/invites/{id}/resend
     */
    public function resendInvite(Request $request, int $id): JsonResponse
    {
        $user = $request->user();
        $workspace = $user->active_workspace_id
            ? Workspace::find($user->active_workspace_id)
            : null;
        if (!$workspace) {
            return response()->json(['message' => 'No active workspace.'], 422);
        }
        if (!in_array($user->workspaceRole($workspace->id), ['owner', 'admin'], true)) {
            return response()->json(['message' => 'Only owners and admins can resend invites.'], 403);
        }

        $invite = DB::table('workspace_invites')
            ->where('workspace_id', $workspace->id)
            ->where('id', $id)
            ->first();
        if (!$invite) {
            return response()->json(['message' => 'Invite not found.'], 404);
        }

        $newToken = Str::random(64);
        DB::table('workspace_invites')->where('id', $id)->update([
            'token'      => $newToken,
            'status'     => 'pending',
            'expires_at' => now()->addDays(7),
            'updated_at' => now(),
        ]);

        $this->sendInviteEmail($workspace, $invite->email, $newToken);

        return response()->json([
            'message' => "Invitation resent to {$invite->email}.",
        ]);
    }

    /**
     * DELETE /api/v1/mobile/team/invites/{id}
     */
    public function cancelInvite(Request $request, int $id): JsonResponse
    {
        $user = $request->user();
        $workspace = $user->active_workspace_id
            ? Workspace::find($user->active_workspace_id)
            : null;
        if (!$workspace) {
            return response()->json(['message' => 'No active workspace.'], 422);
        }
        if (!in_array($user->workspaceRole($workspace->id), ['owner', 'admin'], true)) {
            return response()->json(['message' => 'Only owners and admins can cancel invites.'], 403);
        }

        $updated = DB::table('workspace_invites')
            ->where('workspace_id', $workspace->id)
            ->where('id', $id)
            ->update(['status' => 'cancelled', 'updated_at' => now()]);

        if (!$updated) {
            return response()->json(['message' => 'Invite not found.'], 404);
        }

        return response()->json(['message' => 'Invitation cancelled.']);
    }

    /**
     * PUT /api/v1/mobile/team/members/{userId}
     * Change a member's role. Owner-only.
     */
    public function updateMember(Request $request, int $userId): JsonResponse
    {
        $user = $request->user();
        $workspace = $user->active_workspace_id
            ? Workspace::find($user->active_workspace_id)
            : null;
        if (!$workspace) {
            return response()->json(['message' => 'No active workspace.'], 422);
        }

        if ($user->workspaceRole($workspace->id) !== 'owner') {
            return response()->json(['message' => 'Only the workspace owner can change roles.'], 403);
        }

        $validator = Validator::make($request->all(), [
            'role' => ['required', 'string', 'in:admin,agent,viewer'],
        ]);
        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()], 422);
        }

        if ($userId === $user->id) {
            return response()->json(['message' => 'You cannot change your own role.'], 422);
        }

        $targetRole = DB::table('workspace_members')
            ->where('workspace_id', $workspace->id)
            ->where('user_id', $userId)
            ->value('role');

        if (!$targetRole) {
            return response()->json(['message' => 'Member not found.'], 404);
        }
        if ($targetRole === 'owner') {
            return response()->json(['message' => "Cannot change the workspace owner's role."], 422);
        }

        DB::table('workspace_members')
            ->where('workspace_id', $workspace->id)
            ->where('user_id', $userId)
            ->update(['role' => $request->input('role'), 'updated_at' => now()]);

        return response()->json([
            'message' => 'Member role updated.',
            'member'  => [
                'user_id' => $userId,
                'role'    => $request->input('role'),
            ],
        ]);
    }

    /**
     * DELETE /api/v1/mobile/team/members/{userId}
     */
    public function removeMember(Request $request, int $userId): JsonResponse
    {
        $user = $request->user();
        $workspace = $user->active_workspace_id
            ? Workspace::find($user->active_workspace_id)
            : null;
        if (!$workspace) {
            return response()->json(['message' => 'No active workspace.'], 422);
        }
        if (!in_array($user->workspaceRole($workspace->id), ['owner', 'admin'], true)) {
            return response()->json(['message' => 'Only owners and admins can remove members.'], 403);
        }

        if ($userId === $user->id) {
            return response()->json(['message' => 'You cannot remove yourself. Transfer ownership first.'], 422);
        }

        $targetRole = DB::table('workspace_members')
            ->where('workspace_id', $workspace->id)
            ->where('user_id', $userId)
            ->value('role');

        if (!$targetRole) {
            return response()->json(['message' => 'Member not found.'], 404);
        }
        if ($targetRole === 'owner') {
            return response()->json(['message' => 'Cannot remove the workspace owner.'], 422);
        }

        DB::table('workspace_members')
            ->where('workspace_id', $workspace->id)
            ->where('user_id', $userId)
            ->delete();

        // If their active workspace was this one, clear it so they don't
        // land on a workspace they no longer belong to on next login.
        User::where('id', $userId)
            ->where('active_workspace_id', $workspace->id)
            ->update(['active_workspace_id' => null]);

        return response()->json(['message' => 'Team member removed.']);
    }

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

    private function sendInviteEmail(Workspace $workspace, string $email, string $token): void
    {
        $appName  = config('app.name');
        $subject  = "You're invited to {$workspace->name} on {$appName}";
        $acceptUrl = url("/invite/{$token}");
        $textBody = "You've been invited to join {$workspace->name} on {$appName}.\n\n"
            . "Accept your invitation: {$acceptUrl}\n\n"
            . "This invitation expires in 7 days.";
        $htmlBody = nl2br(e($textBody));

        try {
            $account = EmailAccount::where('workspace_id', $workspace->id)
                ->where('status', 'connected')
                ->orderByDesc('is_default')
                ->orderBy('id')
                ->first();

            if ($account) {
                app(EmailSendService::class)->send($account, $email, $subject, $htmlBody);
            } else {
                Mail::raw($textBody, function ($message) use ($email, $subject) {
                    $message->to($email)->subject($subject);
                });
            }
        } catch (\Throwable $e) {
            Log::warning('Mobile TeamController: invite email failed', ['error' => $e->getMessage()]);
        }
    }

    private function initials(?string $name): string
    {
        if (!$name) return '?';
        $parts = preg_split('/\s+/', trim($name));
        return strtoupper(substr($parts[0] ?? '', 0, 1) . substr($parts[1] ?? '', 0, 1)) ?: '?';
    }
}
