<?php

namespace App\Services\MicrosoftGraph;

use App\Models\User;
use App\Models\Committee;
use App\Models\WorkGroup;
use Illuminate\Support\Facades\Log;

/**
 * Service for tracking user membership changes with Microsoft Graph sync
 */
class UserMembershipService
{
    protected $pendingChangeService;

    public function __construct(MsgraphPendingChangeService $pendingChangeService)
    {
        $this->pendingChangeService = $pendingChangeService;
    }

    /**
     * Track when a user joins a committee or workgroup
     */
    public function trackUserJoined($model, User $user, string $membershipType = null): void
    {
        // Only track if the model is published
        if (!$this->shouldTrack($model)) {
            return;
        }

        $this->pendingChangeService->createUserMembershipChange(
            $model,
            'user_joined',
            $user->id,
            null, // no old type for joins
            $membershipType,
            [
                'user_name' => $user->name . ' ' . $user->last_name,
                'user_email' => $user->email,
                'model_title' => $model->title ?? 'Unknown'
            ]
        );

        $modelType = class_basename($model);
        Log::info("📝 User joined {$modelType} - Microsoft Graph sync pending", [
            'model_id' => $model->id,
            'model_title' => $model->title ?? 'Unknown',
            'user_id' => $user->id,
            'user_name' => $user->name . ' ' . $user->last_name,
            'membership_type' => $membershipType,
        ]);
    }

    /**
     * Track when a user leaves a committee or workgroup
     */
    public function trackUserLeft($model, User $user, string $oldMembershipType = null): void
    {
        // Only track if the model is published
        if (!$this->shouldTrack($model)) {
            return;
        }

        $this->pendingChangeService->createUserMembershipChange(
            $model,
            'user_left',
            $user->id,
            $oldMembershipType,
            null, // no new type for leaves
            [
                'user_name' => $user->name . ' ' . $user->last_name,
                'user_email' => $user->email,
                'model_title' => $model->title ?? 'Unknown'
            ]
        );

        $modelType = class_basename($model);
        Log::info("📝 User left {$modelType} - Microsoft Graph sync pending", [
            'model_id' => $model->id,
            'model_title' => $model->title ?? 'Unknown',
            'user_id' => $user->id,
            'user_name' => $user->name . ' ' . $user->last_name,
            'old_membership_type' => $oldMembershipType,
        ]);
    }

    /**
     * Track when a user's membership type changes
     */
    public function trackUserTypeChanged($model, User $user, string $oldType, string $newType): void
    {
        // Only track if the model is published
        if (!$this->shouldTrack($model)) {
            return;
        }

        $this->pendingChangeService->createUserMembershipChange(
            $model,
            'user_type_changed',
            $user->id,
            $oldType,
            $newType,
            [
                'user_name' => $user->name . ' ' . $user->last_name,
                'user_email' => $user->email,
                'model_title' => $model->title ?? 'Unknown'
            ]
        );

        $modelType = class_basename($model);
        Log::info("📝 User membership type changed in {$modelType} - Microsoft Graph sync pending", [
            'model_id' => $model->id,
            'model_title' => $model->title ?? 'Unknown',
            'user_id' => $user->id,
            'user_name' => $user->name . ' ' . $user->last_name,
            'old_type' => $oldType,
            'new_type' => $newType,
        ]);
    }

    /**
     * Sync committees with tracking for a user
     */
    public function syncUserCommittees(User $user, array $committees): void
    {
        // Get current committee memberships with types
        $currentMemberships = $user->committees()
            ->withPivot('type')
            ->get()
            ->mapWithKeys(function ($committee) {
                return [$committee->id => $committee->pivot->type];
            })
            ->toArray();

        // Perform the sync
        $user->committees()->sync($committees);

        // Track changes
        $this->trackMembershipChanges($user, 'committee', $currentMemberships, $committees);
    }

    /**
     * Sync workgroups with tracking for a user
     */
    public function syncUserWorkGroups(User $user, array $workGroups): void
    {
        // Get current workgroup memberships with types
        $currentMemberships = $user->workGroups()
            ->withPivot('type')
            ->get()
            ->mapWithKeys(function ($workGroup) {
                return [$workGroup->id => $workGroup->pivot->type];
            })
            ->toArray();

        // Perform the sync
        $user->workGroups()->sync($workGroups);

        // Track changes
        $this->trackMembershipChanges($user, 'workgroup', $currentMemberships, $workGroups);
    }

    /**
     * Track membership changes for committees or workgroups
     */
    private function trackMembershipChanges(User $user, string $modelType, array $oldMemberships, array $newMemberships): void
    {
        $modelClass = $modelType === 'committee' ? Committee::class : WorkGroup::class;

        // Find users who joined
        foreach ($newMemberships as $modelId => $membershipType) {
            // Handle array format from sync() method
            $membershipTypeValue = is_array($membershipType) ? $membershipType['type'] ?? null : $membershipType;

            if (!isset($oldMemberships[$modelId])) {
                // User joined
                $model = $modelClass::find($modelId);
                if ($model) {
                    $this->trackUserJoined($model, $user, $membershipTypeValue);
                }
            } elseif ($oldMemberships[$modelId] !== $membershipTypeValue) {
                // Membership type changed
                $model = $modelClass::find($modelId);
                if ($model) {
                    $this->trackUserTypeChanged(
                        $model,
                        $user,
                        $oldMemberships[$modelId],
                        $membershipTypeValue
                    );
                }
            }
        }

        // Find users who left
        foreach ($oldMemberships as $modelId => $oldMembershipType) {
            if (!isset($newMemberships[$modelId])) {
                // User left
                $model = $modelClass::find($modelId);
                if ($model) {
                    $this->trackUserLeft($model, $user, $oldMembershipType);
                }
            }
        }
    }

    /**
     * Detach a user from a specific committee with tracking
     */
    public function detachUserFromCommittee(User $user, int $committeeId): void
    {
        // Get current membership type before detaching
        $currentMembership = $user->committees()
            ->withPivot('type')
            ->where('committee_id', $committeeId)
            ->first();

        if ($currentMembership) {
            $membershipType = $currentMembership->pivot->type;

            // Perform the detach
            $user->committees()->detach($committeeId);

            // Track the change
            $committee = Committee::find($committeeId);
            if ($committee) {
                $this->trackUserLeft($committee, $user, $membershipType);
            }
        }
    }

    /**
     * Detach a user from a specific workgroup with tracking
     */
    public function detachUserFromWorkGroup(User $user, int $workGroupId): void
    {
        // Get current membership type before detaching
        $currentMembership = $user->workGroups()
            ->withPivot('type')
            ->where('work_group_id', $workGroupId)
            ->first();

        if ($currentMembership) {
            $membershipType = $currentMembership->pivot->type;

            // Perform the detach
            $user->workGroups()->detach($workGroupId);

            // Track the change
            $workGroup = WorkGroup::find($workGroupId);
            if ($workGroup) {
                $this->trackUserLeft($workGroup, $user, $membershipType);
            }
        }
    }

    /**
     * Sync user memberships when member memberships change
     * This is called when a Member's committee/workgroup memberships are updated
     * and we need to remove users from committees/workgroups that their member is no longer part of
     */
    public function syncUsersBasedOnMemberMemberships(int $memberId): void
    {
        $users = User::where('member_id', $memberId)->get();

        if ($users->isEmpty()) {
            return;
        }

        // Get member's current committee memberships
        $memberCommittees = \DB::table('committee_member')
            ->where('member_id', $memberId)
            ->pluck('committee_id')
            ->toArray();

        // Get member's current workgroup memberships
        $memberWorkGroups = \DB::table('member_work_group')
            ->where('member_id', $memberId)
            ->pluck('work_group_id')
            ->toArray();

        foreach ($users as $user) {
            // Find user committees that are no longer available due to member changes
            $userCommitteesToRemove = $user->committees()
                ->whereNotIn('committee_id', $memberCommittees)
                ->get();

            foreach ($userCommitteesToRemove as $committee) {
                $membershipType = $committee->pivot->type;
                $user->committees()->detach($committee->id);
                $this->trackUserLeft($committee, $user, $membershipType);
            }

            // Find user workgroups that are no longer available due to member changes
            $userWorkGroupsToRemove = $user->workGroups()
                ->whereNotIn('work_group_id', $memberWorkGroups)
                ->get();

            foreach ($userWorkGroupsToRemove as $workGroup) {
                $membershipType = $workGroup->pivot->type;
                $user->workGroups()->detach($workGroup->id);
                $this->trackUserLeft($workGroup, $user, $membershipType);
            }
        }
    }

    /**
     * Check if we should track changes for this model
     */
    private function shouldTrack($model): bool
    {
        // Only track published committees/workgroups
        if (method_exists($model, 'website_object') && $model->website_object) {
            return $model->website_object->status === 'published';
        }

        // Fallback check for published status
        return isset($model->status) && $model->status === 'published';
    }
}
