<?php

namespace App\Http\Controllers\Api\V1\Admin;

use App\Enums\UserRole;
use App\Enums\UserStatus;
use App\Exceptions\DomainException;
use App\Http\Controllers\Controller;
use App\Http\Resources\DoctorResource;
use App\Models\Doctor;
use App\Models\User;
use App\Services\AuditService;
use App\Support\ApiResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class DoctorAdminController extends Controller
{
    use ApiResponse;

    public function __construct(private readonly AuditService $audit) {}

    public function index(Request $request)
    {
        return $this->success(DoctorResource::collection(
            Doctor::with('user')
                ->where('organization_id', $request->user()->organization_id)
                ->orderByDesc('id')
                ->get()
        ));
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:150'],
            'email' => ['required', 'email', 'max:190'],
            'phone' => ['nullable', 'string', 'max:40'],
            'password' => ['required', 'string', 'min:8', 'max:255'],
            'specialization' => ['required', 'string', 'max:150'],
            'qualification' => ['nullable', 'string', 'max:190'],
            'experience_years' => ['nullable', 'integer', 'min:0', 'max:100'],
            'registration_no' => ['nullable', 'string', 'max:100'],
            'bio' => ['nullable', 'string', 'max:5000'],
        ]);

        $doctor = DB::transaction(function () use ($request, $data) {
            $exists = User::query()
                ->where('organization_id', $request->user()->organization_id)
                ->where('email', $data['email'])
                ->exists();

            if ($exists) {
                throw new DomainException('EMAIL_ALREADY_IN_USE', 'This email is already used in the organization.', 409);
            }

            $user = User::create([
                'organization_id' => $request->user()->organization_id,
                'name' => $data['name'],
                'email' => $data['email'],
                'phone' => $data['phone'] ?? null,
                'password' => $data['password'],
                'role' => UserRole::DOCTOR,
                'status' => UserStatus::ACTIVE,
            ]);

            return Doctor::create([
                'organization_id' => $request->user()->organization_id,
                'user_id' => $user->id,
                'specialization' => $data['specialization'],
                'qualification' => $data['qualification'] ?? null,
                'experience_years' => $data['experience_years'] ?? null,
                'registration_no' => $data['registration_no'] ?? null,
                'bio' => $data['bio'] ?? null,
                'is_active' => true,
            ]);
        });

        $this->audit->log('doctor.created', $request->user(), $doctor, null, $doctor->load('user')->toArray());

        return $this->success(new DoctorResource($doctor->load('user')), 'Doctor created.', 201);
    }

    public function update(Request $request, Doctor $doctor)
    {
        if ($doctor->organization_id !== $request->user()->organization_id) {
            throw new DomainException('FORBIDDEN', 'Doctor belongs to another organization.', 403);
        }

        $data = $request->validate([
            'name' => ['sometimes', 'string', 'max:150'],
            'email' => ['sometimes', 'email', 'max:190'],
            'phone' => ['nullable', 'string', 'max:40'],
            'password' => ['nullable', 'string', 'min:8', 'max:255'],
            'specialization' => ['sometimes', 'string', 'max:150'],
            'qualification' => ['nullable', 'string', 'max:190'],
            'experience_years' => ['nullable', 'integer', 'min:0', 'max:100'],
            'registration_no' => ['nullable', 'string', 'max:100'],
            'bio' => ['nullable', 'string', 'max:5000'],
            'is_active' => ['sometimes', 'boolean'],
            'status' => ['sometimes', 'in:active,disabled,suspended'],
        ]);

        $before = $doctor->load('user')->toArray();

        if (isset($data['email'])) {
            $emailInUse = User::query()
                ->where('organization_id', $request->user()->organization_id)
                ->where('email', strtolower(trim($data['email'])))
                ->whereKeyNot($doctor->user_id)
                ->exists();

            if ($emailInUse) {
                throw new DomainException('EMAIL_ALREADY_IN_USE', 'This email is already used in the organization.', 409);
            }
        }

        DB::transaction(function () use ($doctor, $data) {
            $doctorFields = array_intersect_key($data, array_flip([
                'specialization', 'qualification', 'experience_years', 'registration_no', 'bio', 'is_active',
            ]));
            $doctor->update($doctorFields);

            $userFields = array_intersect_key($data, array_flip(['name', 'email', 'phone', 'password', 'status']));
            if (($data['is_active'] ?? true) === false && ! isset($userFields['status'])) {
                $userFields['status'] = 'disabled';
            }
            if ($userFields) {
                $doctor->user->update($userFields);
            }
        });

        $doctor->refresh()->load('user');
        $this->audit->log('doctor.updated', $request->user(), $doctor, $before, $doctor->toArray());

        return $this->success(new DoctorResource($doctor), 'Doctor updated.');
    }

    public function destroy(Request $request, Doctor $doctor)
    {
        return $this->update($request->merge(['is_active' => false, 'status' => 'disabled']), $doctor);
    }
}
