<?php

namespace App\Http\Controllers\Api\Provider;

use App\Http\Controllers\Api\Traits\ApiResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Provider\LoginProviderRequest;
use App\Http\Requests\Api\Provider\RecoverProviderPasswordRequest;
use App\Http\Requests\Api\Provider\RegisterProviderRequest;
use App\Http\Requests\Api\Provider\ResetProviderPasswordRequest;
use App\Http\Requests\Api\Provider\ChangeContactDetailsRequest;
use App\Http\Requests\Api\Provider\SendVerificationCodeRequest;
use App\Http\Resources\ServiceProviderResource;
use App\Models\ServiceProvider;
use App\Notifications\ConfirmEmailNotification;
use App\Notifications\ForgetPasswordEmailNotification;
use App\Notifications\ForgetPasswordSMSNotification;
use App\Services\SmsService;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Password;
use OpenApi\Annotations as OA;

class ProviderAuthController extends Controller
{
    use ApiResponse;

    public function __construct(protected SmsService $smsService) {}
    /**
     * @OA\Post(
     *     path="/api/provider/register",
     *     summary="Register a new service provider",
     *     tags={"Provider Authentication"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"name", "email", "phone", "password", "password_confirmation", "nationality_id", "id_number", "commercial_register_type", "commercial_register_number"},
     *             @OA\Property(property="name", type="string", example="Service Provider Name"),
     *             @OA\Property(property="email", type="string", format="email", example="provider@example.com"),
     *             @OA\Property(property="phone", type="string", example="966512345678"),
     *             @OA\Property(property="password", type="string", format="password", example="password"),
     *             @OA\Property(property="password_confirmation", type="string", format="password", example="password"),
     *             @OA\Property(property="nationality_id", type="integer", example=1),
     *             @OA\Property(property="has_commercial_register", type="boolean", example=true),
     *             @OA\Property(property="id_number", type="string", example="1234567890"),
     *             @OA\Property(property="commercial_register_type", type="string", enum={"commercial_register", "freelance_document"}, example="commercial_register"),
     *             @OA\Property(property="commercial_register_number", type="string", example="1234567890"),
     *             @OA\Property(property="category_id", type="integer", example=1),
     *             @OA\Property(property="cities", type="array", @OA\Items(type="integer"), example={1, 2})
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Provider registered successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object", nullable=true),
     *             @OA\Property(property="message", type="string", example="Registration successful.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=422,
     *         description="Validation error"
     *     )
     * )
     */
    public function register(RegisterProviderRequest $request)
    {
        $provider = ServiceProvider::create($request->safe()->except('cities') + ['is_active' => false]);
        $provider->cities()->attach($request->cities);

        return $this->successResponse(null, __('messages.registration_successful'));
    }

    /**
     * @OA\Post(
     *     path="/api/provider/login",
     *     summary="Login a service provider",
     *     tags={"Provider Authentication"},
     *     security={{"bearerAuth":{}}},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"email", "password"},
     *             @OA\Property(property="email", type="string", example="provider@example.com or 966512345678", description="Provider's email or phone number"),
     *             @OA\Property(property="password", type="string", format="password", example="password")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Provider logged in successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object",
     *                 @OA\Property(property="access_token", type="string"),
     *                 @OA\Property(property="token_type", type="string", example="Bearer"),
     *                 @OA\Property(property="provider", ref="#/components/schemas/ServiceProviderResource")
     *             ),
     *             @OA\Property(property="message", type="string", example="Login successful.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=401,
     *         description="Invalid credentials"
     *     ),
     *     @OA\Response(
     *         response=422,
     *         description="Validation error"
     *     )
     * )
     */
    public function login(LoginProviderRequest $request)
    {
        $provider = ServiceProvider::where('email', $request->email)->orWhere('phone', $request->email)->first();

        if (!$provider || !Hash::check($request->password, $provider->password)) {
            return $this->errorResponse(__('messages.invalid_credentials'), 401);
        }

        if (!$provider->is_active) {
            return $this->errorResponse(__('messages.provider_not_active'), 403);
        }

        $token = $provider->createToken('auth_token')->plainTextToken;

        return $this->successResponse([
            'access_token' => $token,
            'token_type' => 'Bearer',
            'provider' => $provider->load(['cities', 'nationality', 'category'])
        ], __('messages.login_successful'));
    }

    /**
     * @OA\Post(
     *     path="/api/provider/password/forgot",
     *     summary="Forgot provider password",
     *     tags={"Provider Authentication"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"email"},
     *             @OA\Property(property="email", type="string", example="provider@example.com or 966512345678", description="Provider's email or phone number"),
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Password recovery token sent",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="message", type="string", example="Password reset token sent.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=422,
     *         description="Validation error"
     *     )
     * )
     */
    public function forgotPassword(RecoverProviderPasswordRequest $request)
    {
        $provider = ServiceProvider::where('email', $request->email)
            ->orWhere("phone", $request->email)
            ->first();

        if (!$provider) {
            return $this->errorResponse(__('messages.provider_not_found'), 400);
        }

        $token = strval(rand(1000, 9999));
        if (!app()->isProduction()) {
            $token = "0000";
        }
        DB::table('password_reset_tokens')->updateOrInsert(
            ['email' => $request->email],
            [
                'token' => Hash::make($token),
                'created_at' => Carbon::now()
            ]
        );

        // $provider->sendPasswordResetNotification($token);
        if ($request->email == $provider->email) {
            $provider->notify(new ForgetPasswordEmailNotification($provider->name, $provider->email, $token));
        } elseif ($request->type === 'sms') {
            if (app()->isProduction())
                $this->smsService->send($provider->phone, "Your OTP is: {$token}");
            // $provider->notify(new ForgetPasswordSMSNotification($provider->name, $provider->phone, $token));
        }

        return $this->successResponse(null, __('messages.password_reset_token_sent'));
    }

    /**
     * @OA\Post(
     *     path="/api/provider/password/reset",
     *     summary="Reset provider password",
     *     tags={"Provider Authentication"},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"email", "token"},
     *             @OA\Property(property="email", type="string", example="provider@example.com or 966512345678", description="Provider's email or phone number"),
     *             @OA\Property(property="token", type="string", example="123456"),
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Password has been reset",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object",
     *                 @OA\Property(property="access_token", type="string"),
     *                 @OA\Property(property="token_type", type="string", example="Bearer"),
     *                 @OA\Property(property="provider", ref="#/components/schemas/ServiceProviderResource")
     *             ),
     *             @OA\Property(property="message", type="string", example="Password reset successful.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=422,
     *         description="Validation error"
     *     )
     * )
     */
    public function resetPassword(ResetProviderPasswordRequest $request)
    {
        $resetRecord = DB::table('password_reset_tokens')
            ->where('email', $request->email)
            ->first();

        if (!$resetRecord) {
            return $this->errorResponse(__('messages.invalid_token'), 400);
        }
        if (!Hash::check($request->token, $resetRecord->token)) {
            return $this->errorResponse(__('messages.invalid_token'), 400);
        }

        // if passes 10 minutes
        if (Carbon::now()->diffInMinutes($resetRecord->created_at) > 10) {
            return $this->errorResponse(__('messages.token_expired'), 400);
        }

        $provider = ServiceProvider::where('email', $request->email)
            ->orWhere('phone', $request->email)
            ->first();
        if (!$provider) {
            return $this->errorResponse(__('messages.provider_not_found'), 404);
        }

        // $provider->password = Hash::make($request->password);
        // $provider->save();

        $token = $provider->createToken('auth_token')->plainTextToken;

        DB::table('password_reset_tokens')->where('email', $request->email)->delete();

        if (! $provider->is_active) {
            return $this->errorResponse(__('messages.password_reset_successful_but_provider_inactive'));
        }

        return $this->successResponse([
            'access_token' => $token,
            'token_type' => 'Bearer',
            'provider' => $provider->load(['cities', 'nationality', 'category'])
        ], __('messages.reset_code_is_correct'));


        // return $this->successResponse(null, __('messages.password_reset_successful'));
    }

    /**
     * @OA\Post(
     *     path="/api/provider/password/send-verification-code",
     *     summary="Send verification code for contact detail change",
     *     description="Sends a verification code to the new email or phone number. The code is used to verify the change in the 'Change Contact Details' endpoint.",
     *     tags={"Provider Profile"},
     *     security={{"bearerAuth":{}}},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         description="Provide either the new email or new phone, but not both. The new contact detail must be unique.",
     *         @OA\JsonContent(
     *             @OA\Property(property="phone", type="string", example="9665xxxxxxx"),
     *             oneOf={
     *                 @OA\Schema(required={"email"}, @OA\Property(property="email", type="string", format="email", example="new.provider@example.com")),
     *                 @OA\Schema(required={"phone"}, @OA\Property(property="phone", type="string", example="966512345679"))
     *             }
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Verification code sent successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object", nullable=true),
     *             @OA\Property(property="message", type="string", example="Verification code sent.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=401,
     *         description="Unauthenticated"
     *     ),
     *     @OA\Response(
     *         response=422,
     *         description="Validation error"
     *     )
     * )
     */
    public function sendVerificationCode(SendVerificationCodeRequest $request)
    {

        $email = $request->input("email");
        $phone = $request->input('phone');

        $identifier = $email ?? $phone;
        $provider = $request->user();

        $token = strval(rand(1000, 9999));
        if (!app()->isProduction()) {
            $token = "0000";
        }
        DB::table('password_reset_tokens')->updateOrInsert(
            ['email' => $identifier],
            [
                'token' => Hash::make($token),
                'created_at' => Carbon::now()
            ]
        );

        if ($email) {
            Notification::route('mail', $email)
                ->notify(new ConfirmEmailNotification($provider->name, $email, $token));
        } elseif ($phone) {
            if (app()->isProduction())
                $this->smsService->send($provider->phone, "Your OTP is: {$token}");
            // $provider->notify(new ForgetPasswordSMSNotification($provider->name, $provider->phone, $token));
        }

        return $this->successResponse(null, __('messages.password_reset_token_sent'));
    }

    /**
     * @OA\Post(
     *     path="/api/provider/profile/change-contact-details",
     *     summary="Change provider's contact details",
     *     description="Updates the provider's email or phone number after verifying the code received from the 'Send verification code' endpoint.",
     *     tags={"Provider Profile"},
     *     security={{"bearerAuth":{}}},
     *     @OA\Parameter(
     *         name="Accept-Language",
     *         in="header",
     *         required=false,
     *         description="Language preference (e.g., 'en', 'ar')",
     *         @OA\Schema(type="string", enum={"en", "ar"}, default="en")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         description="Provide the verification code and either the new email or new phone that the code was sent to.",
     *         @OA\JsonContent(
     *             required={"code"},
     *             @OA\Property(property="code", type="string", example="0000"),
     *             @OA\Property(property="phone", type="string", example="9665xxxxxxx"),
     *             oneOf={
     *                 @OA\Schema(required={"email"}, @OA\Property(property="email", type="string", format="email", example="new.provider@example.com")),
     *                 @OA\Schema(required={"phone"}, @OA\Property(property="phone", type="string", example="966512345679"))
     *             }
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Contact details updated successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="success", type="boolean", example=true),
     *             @OA\Property(property="data", type="object", nullable=true),
     *             @OA\Property(property="message", type="string", example="Profile updated.")
     *         )
     *     ),
     *     @OA\Response(
     *         response=400,
     *         description="Invalid or expired token"
     *     ),
     *     @OA\Response(
     *         response=401,
     *         description="Unauthenticated"
     *     ),
     *     @OA\Response(
     *         response=422,
     *         description="Validation error"
     *     )
     * )
     */
    public function changeContactDetails(ChangeContactDetailsRequest $request)
    {
        $email = $request->input("email");
        $phone = $request->input('phone');

        $identifier = $email ?? $phone;


        $provider = $request->user();

        $resetRecord = DB::table('password_reset_tokens')
            ->where('email', $identifier)
            ->first();

        if (!$resetRecord) {
            return $this->errorResponse(__('messages.invalid_token'), 400);
        }
        if (!Hash::check($request->code, $resetRecord->token)) {
            return $this->errorResponse(__('messages.invalid_token'), 400);
        }

        if (Carbon::now()->diffInMinutes($resetRecord->created_at) > 10) {
            return $this->errorResponse(__('messages.token_expired'), 400);
        }

        if ($request->has('email')) {
            $provider->email = $request->email;
        }

        if ($request->has('phone')) {
            $provider->phone = $request->phone;
        }

        $provider->save();

        DB::table('password_reset_tokens')->where('email', $identifier)->delete();

        return $this->successResponse(ServiceProviderResource::make($provider), __('messages.profile_updated'));
    }
}
