<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\ApiBaseController;
use App\Models\FaceRegistration;
use App\Models\StaffMember;
use App\Models\User;
use Examyou\RestAPI\ApiResponse;
use Examyou\RestAPI\Exceptions\ApiException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use App\Classes\Common;
use App\Classes\CommonHrm;

class FaceController extends ApiBaseController
{
    /**
     * Ensure the logged-in manager/admin can access the given user.
     */
    protected function ensureManagerCanAccessUser(int $userId): StaffMember
    {
        $loggedUser = user();

        if (
            (!$loggedUser->is_manager && !$loggedUser->ability('admin', 'users_edit')) ||
            !$loggedUser->role
        ) {
            throw new ApiException("Don't have valid permission");
        }

        $userQuery = StaffMember::where('id', $userId)
            ->where('company_id', company()->id);

        $userQuery = CommonHrm::applyVisibility($userQuery);

        $user = $userQuery->first();

        if (!$user) {
            throw new ApiException('User not found or not accessible', null, 404, 404);
        }

        return $user;
    }

    /**
     * Apply visibility rules (CommonHrm) with a fallback for managers whose visibility is not set.
     */
    protected function applyUserVisibility($query, string $tableName, string $userIdField)
    {
        $loggedUser = user();
        $query = CommonHrm::applyVisibility($query, $tableName, $userIdField);

        // Fallback: managers with no visibility configured should still only see their reports.
        $needsManagerFallback = $loggedUser->is_manager
            && $loggedUser->role?->name !== 'admin'
            && in_array($loggedUser->visibility, [null, '', 'none'], true);

        if ($needsManagerFallback) {
            if ($tableName !== 'users') {
                $query->join('users', 'users.id', '=', $tableName . '.' . $userIdField);
            }

            $query->where(function ($managerQuery) use ($loggedUser) {
                $managerQuery->where('users.report_to', $loggedUser->id)
                    ->whereNotNull('users.report_to');
            });
        }

        return $query;
    }

    /**
     * GET /api/users/missing-faces
     * Return users without face_id data
     */
    public function missingFaces(Request $request)
    {
        try {
            $companyId = company()->id;
            
            // Get users who don't have face registrations with visibility applied
            $usersWithoutFacesQuery = User::where('company_id', $companyId)
                ->where('user_type', 'staff_members')
                ->whereDoesntHave('faceRegistrations', function ($query) use ($companyId) {
                    $query->where('company_id', $companyId);
                });

            $usersWithoutFacesQuery = $this->applyUserVisibility($usersWithoutFacesQuery, 'users', 'id');

            $usersWithoutFaces = $usersWithoutFacesQuery
                ->with(['company', 'location', 'designation', 'department'])
                ->select('id', 'name', 'location_id', 'designation_id', 'department_id', 'email', 'employee_number', 'profile_image', 'company_id')
                ->get()
                ->map(function ($user) {
                    return [
                        'id' => $user->xid,
                        'company_id' => $user->company?->xid ?? null,
                        'location_id' => $user->location?->xid ?? null,
                        'designation_id' => $user->designation?->xid ?? null,
                        'department_id' => $user->department?->xid ?? null,
                        'name' => $user->name,
                        'email' => $user->email,
                        'employee_number' => $user->employee_number,
                        'profile_image_url' => $user->profile_image_url,
                        'location' => $user->location?->name ?? null,
                        'designation' => $user->designation?->name ?? null,
                        'department' => $user->department?->name ?? null,
                    ];
                });

            return ApiResponse::make('Success', [
                'users' => $usersWithoutFaces,
                'count' => $usersWithoutFaces->count()
            ]);
        } catch (\Exception $e) {
            throw new ApiException('Failed to fetch users without faces', null, 500, 500, $e);
        }
    }

    /**
     * GET /api/face/sync
     * Return all face registration data for a company
     * Filtered by team/hierarchy visibility (manager, department, location)
     */
    public function sync(Request $request)
    {
        try {
            $companyId = company()->id;
            
            // Start with face registrations query
            $faceRegistrationsQuery = FaceRegistration::where('face_registrations.company_id', $companyId);
            
            // Apply visibility filtering (team/hierarchy based on logged-in user's permissions)
            $faceRegistrationsQuery = $this->applyUserVisibility($faceRegistrationsQuery, 'face_registrations', 'user_id');
            
            // Execute query with eager loading
            $faceRegistrations = $faceRegistrationsQuery
                ->with(['user:id,name,email,employee_number'])
                ->get();

            $faceRegistrations = $faceRegistrations->map(function ($registration) {
                return [
                    'id' => $registration->xid,
                    'user_id' => $registration->user?->xid ?? null,
                        'company_id' => $registration->company?->xid ?? null,
                        'face_data' => $registration->getDecryptedFaceData(),
                        'user' => $registration->user ? [
                            'id' => $registration->user->xid ?? null,
                            'company_id' => $registration->company?->xid ?? null,
                            'name' => $registration->user->name,
                            'email' => $registration->user->email,
                            'employee_number' => $registration->user->employee_number,
                        ] : null,
                        'created_at' => $registration->created_at,
                        'updated_at' => $registration->updated_at,
                    ];
                });

            return ApiResponse::make('Success', [
                'faces' => $faceRegistrations,
                'count' => $faceRegistrations->count()
            ]);
        } catch (\Exception $e) {
            throw new ApiException('Failed to sync face data', null, 500, 500, $e);
        }
    }

    /**
     * POST /api/face/register
     * Register user face data
     */
    public function register(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'user_id' => 'required',
                'company_id' => 'required',
                'face_data' => 'required|string',
            ]);

            if ($validator->fails()) {
                throw new ApiException('Validation failed', null, 422, 422, null, $validator->errors()->toArray());
            }

            $userId = Common::getIdFromHash($request->user_id);
            $companyId = Common::getIdFromHash($request->company_id);
            $faceData = $request->face_data;

            // Verify user belongs to company

            $user = User::where('id', $userId)
                ->where('company_id', $companyId)
                ->first();

            if (!$user) {
                throw new ApiException('User not found or does not belong to company', null, 404, 404);
            }

            // Check if face registration already exists
            $existingRegistration = FaceRegistration::where('user_id', $userId)
                ->where('company_id', $companyId)
                ->first();

            if ($existingRegistration) {
                // Update existing registration
                $existingRegistration->face_data = $faceData;
                $existingRegistration->save();
                
                return ApiResponse::make('Face data updated successfully', [
                    'face_registration' => [
                        'id' => $existingRegistration->xid,
                        'user_id' => $existingRegistration->user?->xid ?? null,
                        'company_id' => $existingRegistration->company?->xid ?? null,
                        'created_at' => $existingRegistration->created_at,
                        'updated_at' => $existingRegistration->updated_at,
                    ]
                ]);
            } else {
                // Create new registration
                $faceRegistration = new FaceRegistration();
                $faceRegistration->user_id = $userId;
                $faceRegistration->company_id = $companyId;
                $faceRegistration->face_data = $faceData;
                $faceRegistration->save();

                return ApiResponse::make('Face data registered successfully', [
                    'face_registration' => [
                        'id' => $faceRegistration->xid,
                        'user_id' => $faceRegistration->user?->xid ?? null,
                        'company_id' => $faceRegistration->company?->xid ?? null,
                        'created_at' => $faceRegistration->created_at,
                        'updated_at' => $faceRegistration->updated_at,
                    ]
                ]);
            }
        } catch (ApiException $e) {
            throw $e;
        } catch (\Exception $e) {
            throw new ApiException('Failed to register face data', null, 500, 500, $e);
        }
    }

    /**
     * GET /api/face/registration/{user_id}
     * Fetch face registration status for a specific user
     */
    public function showUserFaceRegistration(string $xUserId)
    {
        try {
            $userId = Common::getIdFromHash($xUserId);
            $this->ensureManagerCanAccessUser($userId);

            $companyId = company()->id;
            $faceRegistration = FaceRegistration::where('user_id', $userId)
                ->where('company_id', $companyId)
                ->first();

            return ApiResponse::make('Success', [
                'registered' => (bool) $faceRegistration,
                'face_registration' => $faceRegistration ? [
                    'id' => $faceRegistration->xid,
                    'user_id' => $faceRegistration->user?->xid,
                    'company_id' => $faceRegistration->company?->xid,
                    'created_at' => $faceRegistration->created_at,
                    'updated_at' => $faceRegistration->updated_at,
                ] : null,
            ]);
        } catch (ApiException $e) {
            throw $e;
        } catch (\Exception $e) {
            throw new ApiException('Failed to fetch face registration', null, 500, 500, $e);
        }
    }

    /**
     * DELETE /api/face/registration/{user_id}
     * Clear face registration for a specific user
     */
    public function clearUserFaceRegistration(string $xUserId)
    {
        try {
            $userId = Common::getIdFromHash($xUserId);
            $user = $this->ensureManagerCanAccessUser($userId);

            $companyId = company()->id;

            $existingRegistration = FaceRegistration::where('user_id', $userId)
                ->where('company_id', $companyId)
                ->first();

            if (!$existingRegistration) {
                return ApiResponse::make('No face registration found', [
                    'cleared' => false,
                    'face_registration' => null,
                ]);
            }

            DB::transaction(function () use ($existingRegistration) {
                $existingRegistration->delete();
            });

            return ApiResponse::make('Face registration cleared successfully', [
                'cleared' => true,
                'face_registration' => null,
                'user' => [
                    'id' => $user->xid,
                ],
            ]);
        } catch (ApiException $e) {
            throw $e;
        } catch (\Exception $e) {
            throw new ApiException('Failed to clear face registration', null, 500, 500, $e);
        }
    }
}

