<?php

namespace App\Controllers\Api\V1;

use Exception;
use App\Models\UsersModel;
use App\Models\RSAUsersModel;
use App\Models\InsuranceUserModel;
use App\Controllers\BaseController;
use App\Models\PatientProfileModel;
use App\Models\InsuranceProductsModel;
use App\Models\WeeklySubscriptionModel;
use CodeIgniter\HTTP\ResponseInterface;

class AuthRegisterController extends BaseController
{
    protected  $userModel;
    protected  $rsaUserModel;
    protected  $insuranceUserModel;
    protected  $weeklySubscriptionModel;
    protected  $patientProfileModel;
    protected  $InsuranceProductsModel;

    public function __construct()
    {
        $this->userModel = new UsersModel();
        $this->rsaUserModel = new RSAUsersModel();
        $this->insuranceUserModel = new InsuranceUserModel();
        $this->weeklySubscriptionModel = new WeeklySubscriptionModel();
        $this->patientProfileModel = new PatientProfileModel();
        $this->InsuranceProductsModel = new InsuranceProductsModel();
    }

    public function registerOrLogin()
    {
        try {
            $rules = [
                'phone' => 'required|min_length[4]|max_length[255]',
            ];
            $errors = [
                'phone' => [
                    'required' => 'Phone number field is required.',
                ],
            ];

            $input = $this->getApiGetRequestInput($this->request);
            if (!$this->validateApiRequest($input, $rules, $errors)) {
                return $this
                    ->getApiResponse(
                        [
                            'statusCode' => 3,
                            'message' => array_values($this->validator->getErrors()),
                        ],
                        ResponseInterface::HTTP_OK
                    );
            }
            $userData = $this->validateUser($input);
            if (!empty($userData)) {
                $userData['package'] = $this->getSubscription($userData['Id']);
                return $this
                    ->getApiResponse(
                        [
                            'statusCode' => 1,
                            'message' => 'User authenticated successfully.',
                            'data' => $userData,
                        ]
                    );
            } else {
                $uId = generateGUID();
                $data = [
                    'Id' => $uId,
                    'Email' => $input['phone'] . '@webdoc.com',
                    'EmailConfirmed' => 0,
                    'PasswordHash' => $this->passwordCustomHashing('webdoc@123'),
                    'SecurityStamp' => $input['securitystamp'] ?? NULL,
                    'PhoneNumber' => $input['phone'],
                    'PhoneNumberConfirmed' => 0,
                    'TwoFactorEnabled' => 0,
                    'LockoutEndDateUtc' => NULL,
                    'LockoutEnabled' => 1,
                    'AccessFailedCount' => 0,
                    'UserName' => 'Zindigi',
                    'Role' => 'ZindigiClient',
                ];
                $this->userModel->insert($data);
                // $this->rsaUserModel->insert($data);
                // $this->insuranceUserModel->insert($data);

                $patientData = [
                    'ApplicationUserId' => $uId,
                    'FirstName' => 'Zindigi',
                    'LastName' => 'User',
                    'CNIC' => '000000000000',
                    'DateOfBirth' => date('Y-m-d H:i:s'),
                    'Gender' => '--',
                    'Address' => '--',
                    'Country' => 'Pakistan',
                    'City' => '--',
                    'MobileNumber' => $input['phone'],
                    'freecall' => 1,
                ];
                $this->patientProfileModel->insert($patientData);

                $userData = $this->userModel->findUserByPhoneNumber($input['phone']);
                $userData['package'] = $this->getSubscription($userData['Id']);
                return $this
                    ->getApiResponse(
                        [
                            'statusCode' => 1,
                            'message' => 'User has been registerd successfully.',
                            'data' => $userData,
                        ]
                    );
            }
        } catch (Exception $e) {
            return $this->getApiResponse(
                [
                    'statusCode' => 3,
                    'message' => $e->getMessage()
                ],
            );
        }
    }

    private function passwordCustomHashing($password)
    {
        if ($password === null) {
            throw new Exception("Password cannot be null");
        }
        $salt = random_bytes(16);
        $key = hash_pbkdf2("sha1", $password, $salt, 1000, 32, true);
        $hashedPassword = chr(strlen($salt)) . $salt . $key;
        $encodedHashedPassword = base64_encode($hashedPassword);
        return $encodedHashedPassword;
    }


    public function validateUser($data)
    {

        $user = $this->userModel->findUserByPhoneNumber($data['phone']);
        if (!empty($user) && $this->verifyHashedPassword($user['PasswordHash'], 'webdoc@123')) {
            return $user;
        }
        return null;
    }


    private function verifyHashedPassword($hashedPassword, $password)
    {
        if ($hashedPassword === null) {
            return false;
        }
        if ($password === null) {
            throw new Exception("Password cannot be null");
        }
        $src = base64_decode($hashedPassword);

        $dst = substr($src, 1, 16);

        $buffer3 = substr($src, 17, 32);
        $buffer4 = hash_pbkdf2("sha1", $password, $dst, 1000, 32, true);
        return $this->areHashesEqual($buffer3, $buffer4);
    }

    private function areHashesEqual($firstHash, $secondHash)
    {
        $minHashLength = min(strlen($firstHash), strlen($secondHash));
        $xor = strlen($firstHash) ^ strlen($secondHash);
        for ($i = 0; $i < $minHashLength; $i++) {
            $xor |= ord($firstHash[$i]) ^ ord($secondHash[$i]);
        }
        return $xor === 0;
    }

    private function getSubscription($userId)
    {
        // Get the current date
        $currentDateTime = date('Y-m-d H:i:s');

        $data = $this->weeklySubscriptionModel->select('*')
            ->where('PatientProfileId', $userId)
            ->where('ActiveDate <=', $currentDateTime)
            ->where('ExpiryDate >', $currentDateTime)
            ->first();
        if (!empty($data)) {
            $insurance = $this->InsuranceProductsModel->where('id', $data['InsuranceProductId'])->first();
            $data['packageName'] = $insurance;
        }

        return $data;
    }
}
