<?php

namespace onespace\tools\activeApi\models\oneaccess;

use onespace\tools\activeApi\components\clients\OneAccessClient;
use Override;
use yii\helpers\ArrayHelper;
use yii\web\NotFoundHttpException;

/**
 * This class is intended to be extended from within the child service,
 * though it shouldn't need to be if you just need a basic interface
 * with the method / endpoint without any extra methods.
 *
 * @property integer $id
 * @property string $guid
 * @property string $site_id
 * @property string $site_origin
 * @property string $serial
 * @property string $name
 * @property integer $access_user_id
 * @property integer $state
 * @property string $advanced_state
 * @property string $owner_osid
 * @property string $owner_contact_osid
 * @property string $device_id
 * @property string $property_id
 * @property integer $type_id
 * @property string $start_date
 * @property string $end_date
 * @property string $date_created
 * @property string $last_updated
 * @property string $last_seen
 * @property integer $last_ap_id
 * @property integer $expiry_days
 * @property integer $days_of_week
 * @property integer $person_id
 * @property array $extra
 *
 * @author  Gareth Palmer <gareth@one-space.co.za>
 */
class AccessMethod extends \onespace\tools\activeApi\models\BaseActiveApiModel {
    public $id;
    public $guid;
    public $site_id;
    public $site_origin;
    public $serial;
    public $name;
    public $access_user_id;
    public $state;
    public $advanced_state;
    public $owner_osid;
    public $owner_contact_osid;
    public $device_id;
    public $property_id;
    public $type_id;
    public $start_date;
    public $end_date;
    public $date_created;
    public $last_updated;
    public $last_seen;
    public $last_ap_id;
    public $expiry_days;
    public $days_of_week;
    public $person_id;
    public $extra;

    public const STATUS_PENDING = 1;
    public const STATUS_ACTIVE = 2;
    public const STATUS_DISABLED = 3;
    public const STATUS_PENDING_CONFIRMATION = 4;
    public const STATUS_ARCHIVED = 5;

    public const INTERCOM_MIN = 10;
    public const INTERCOM_MAX = 9999;

    public const RANGE_BIOMETRIC_MIN = 10000;
    public const RANGE_BIOMETRIC_MAX = 99999;

    public const RANGE_BLUETOOTH_MIN = 0xA0000000; // 2684354560
    public const RANGE_BLUETOOTH_MAX = 0xAFFFFFFF; // 2952790015


    /**
     * @note I can see that scenarios would be rather useful here.
     */

    /**
     * {@inheritdoc}
     */
    public function rules() {
        // To be investigated
        return ArrayHelper::merge(parent::rules(), [
            [['site_id', 'name', 'state', 'advanced_state', 'type_id', 'expiry_days'], 'required'], // 'guid',
            ['serial', 'required', 'when' => function ($model) {
                return $model->type_id !== AccessMethodType::TYPE_BIOMETRIC
                    && $model->type_id !== AccessMethodType::TYPE_BLUETOOTH;
            }],
            [['id', 'access_user_id', 'state', 'type_id', 'last_ap_id', 'expiry_days', 'person_id'], 'integer'],
            [['start_date', 'end_date', 'last_updated', 'last_seen', 'date_created', 'extra'], 'safe'],
            [['guid', 'site_id', 'site_origin', 'owner_osid', 'owner_contact_osid', 'property_id'], 'string', 'max' => 36],
            [['serial', 'name', 'device_id'], 'string', 'max' => 255],
            [['days_of_week'], 'safe'],
            [['guid'], 'unique'],
            [['advanced_state'], 'string', 'max' => 10],
            // [['type_id'], 'exist', 'skipOnError' => true, 'targetClass' => \app\models\AccessMethodType::class, 'targetAttribute' => ['type_id' => 'id']]
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels() {
        return [
            'id' => 'ID',
            'guid' => 'Guid',
            'site_id' => 'Estate',
            'serial' => 'Serial',
            'name' => 'Name',
            'type_id' => 'Type',
            'state' => 'State',
            'advanced_state' => 'Advanced State',
            'access_user_id' => 'Access User',
            'owner_osid' => 'Owner',
            'owner_contact_osid' => 'Owner Contact',
            'device_id' => 'Device',
            'property_id' => 'Property',
            'start_date' => 'Start Date',
            'end_date' => 'End Date',
            'date_created' => 'Date Created',
            'last_updated' => 'Last Updated',
            'last_seen' => 'Last Seen',
            'last_ap_id' => 'Last Ap ID',
            'expiry_days' => 'Expiry Days',
            'person_id' => 'Person ID',
            'extra' => 'Extra',
        ];
    }

    public function client(): OneAccessClient {
        return new OneAccessClient();
    }

    public function primaryKey(): string {
        return 'id';
    }

    public function baseEndpoints(): array {
        return [
            'v1' => 'v1/access-method',
            'v2' => 'v2/access-method',
        ];
    }

    public static function getStatuses(): array {
        return [
            self::STATUS_PENDING              => 'Pending',
            self::STATUS_ACTIVE               => 'Enabled',
            self::STATUS_DISABLED             => 'Disabled',
            self::STATUS_PENDING_CONFIRMATION => 'Pending Confirmation',
            self::STATUS_ARCHIVED             => 'Archived',
        ];
    }

    public static function findById(int $id): static {
        $model = self::findOne(['id' => $id]);
        if ($model === null) {
            throw new NotFoundHttpException("Method not found");
        }
        return $model;
    }

    public static function findByGuid(string $guid): static {
        $model = self::findOne(['guid' => $guid]);
        if ($model === null) {
            throw new NotFoundHttpException("Method not found");
        }
        return $model;
    }

    /** @deprecated Don't save this model directly, especially for state changes */
    #[Override]
    public function save(bool $runValidation = true, ?array $attributes = null): bool {
        return parent::save($runValidation, $attributes);
    }
}
