<?php

namespace app\models;

use Yii;
use borales\extensions\phoneInput\PhoneInputValidator;
use kartik\password\StrengthValidator;
use frontend\models\PasswordHistory;
use yii\web\UploadedFile;
/**
 * This is the model class for table "tbl_user".
 *
 * @property int $id table ids
 * @property string $first_name User first name
 * @property string $middle_name User middle name
 * @property string $last_name user last name
 * @property string $username User name 
 * @property string $phone phone number
 * @property string $email User email
 * @property string $nida NIDA Number
 * @property string $salutation
 * @property string $photo
 * @property string $birth_date
 * @property string $auth_key
 * @property string $password_hash User password
 * @property string $last_password_update last password updated date
 * @property string $last_login_date Lat login date
 * @property string $created_at created at
 * @property string $updated_at Updated date
 * @property int $is_deleted 1: No, 2: Yes
 * @property int $is_blocked 1: No 2: Yes
 * @property int $user_type_id type of user foreign key
 * @property int $nationality
 * @property string $sex
 * @property int $photo_size
 * @property int $photo_verified
 * @property string $photo_verified_date
 *
 * @property TblPasswordBlacklisted[] $tblPasswordBlacklisteds
 * @property TblResultsCaHistory[] $tblResultsCaHistories
 * @property TblResultsUeHistory[] $tblResultsUeHistories
 * @property TblStaff[] $tblStaff
 * @property TblStudent[] $tblStudents
 * @property TblStudentBilling[] $tblStudentBillings
 * @property TblUploadHistory[] $tblUploadHistories
 * @property TblUserType $userType
 * @property TblNationality $nation
 */
class TblUser extends \yii\db\ActiveRecord
{

    public $imageFile;

    public $old_password;
	public $new_password;
	public $repeat_password;

    public $password_confirmation;

    public $force_password_change;
    
    /**
     * {@inheritdoc}
     */
    public static function tableName()
    {
        return 'tbl_user';
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [['first_name', 'last_name', 'username','phone', 'auth_key', 'password_hash', 'last_password_update', 'last_login_date', 'created_at', 'user_type_id', 'sex', 'old_password', 'new_password', 'repeat_password','nationality'], 'required'],
            [['birth_date', 'last_password_update', 'last_login_date', 'created_at', 'updated_at', 'photo_size', 'photo_verified', 'photo_verified_date','nida'], 'safe'],
            [['new_password'], StrengthValidator::className(), 
                'min'=>8,
                'upper'=>1,
                'digit'=>2, 
                'special'=>1
            ],
            ['repeat_password', 'compare', 'compareAttribute' => 'new_password', 'message' => 'Password does not match'],
            [['is_deleted', 'is_blocked','salutation', 'user_type_id', 'photo_size','nationality'], 'integer'],
            [['first_name', 'middle_name', 'last_name', 'username', 'email', 'photo', 'password_hash'], 'string', 'max' => 255],
            [['phone', 'sex'], 'string'],
            [['force_password_change'], 'integer'],
            // NIDA Validation Rules - NOT REQUIRED
            [['nida'], 'string', 'max' => 20],
            [['nida'], 'match', 'pattern' => '/^[0-9]{16,20}$/', 'message' => 'NIDA number must contain 16-20 digits only', 'skipOnEmpty' => true],
            // [['nida'], 'unique', 'message' => 'This NIDA number is already registered', 'skipOnEmpty' => true], // Uncomment if NIDA should be unique
            
            [['email'], 'email'],
            [['username'], 'trim'],
            [['email'],'unique'],
            
            // ============================================
            // 🔐 SERVER-SIDE FILE UPLOAD VALIDATION
            // ============================================
            [['imageFile'], 'file', 
                'skipOnEmpty' => true,
                'extensions' => ['jpg', 'jpeg', 'png', 'gif', 'webp'],
                'mimeTypes' => ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'],
                'maxSize' => 2 * 1024 * 1024, // 2MB
                'tooBig' => 'Image must not exceed 2MB.',
                'wrongExtension' => 'Invalid file type. Only JPG, JPEG, PNG, GIF, and WEBP are allowed.',
                'wrongMimeType' => 'Invalid image file detected. File content does not match extension.',
                'maxFiles' => 1,
            ],
            
            [['auth_key'], 'string', 'max' => 32],
            [['salutation'], 'exist', 'skipOnError' => true, 'targetClass' => TblSalutation::className(), 'targetAttribute' => ['salutation' => 'id']],
            [['user_type_id'], 'exist', 'skipOnError' => true, 'targetClass' => TblUserType::className(), 'targetAttribute' => ['user_type_id' => 'id']],
            [['nationality'], 'exist', 'skipOnError' => true, 'targetClass' => TblNationality::className(), 'targetAttribute' => ['nationality' => 'id']],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'first_name' => 'First Name',
            'middle_name' => 'Middle Name',
            'last_name' => 'Last Name',
            'username' => 'Username',
            'phone' => 'Phone',
            'nida' => 'NIDA Number',
            'email' => 'Email',
            'salutation' => 'Salutation',
            'nationality' => 'Nationality',
            'photo' => 'Photo',
            'sex' => 'Sex',
            'birth_date' => 'Birth Date',
            'auth_key' => 'Auth Key',
            'password_hash' => 'Password',
            'password_confirmation' => 'Password Confirmation',
            'last_password_update' => 'Last Password Update',
            'last_login_date' => 'Last Login Date',
            'created_at' => 'Created At',
            'updated_at' => 'Updated At',
            'is_deleted' => 'Is Deleted',
            'is_blocked' => 'Is Blocked',
            'user_type_id' => 'User Type',
        ];
    }

    public function scenarios()
    {
        $scenarios = parent::scenarios();

        $scenarios['create'] = ['first_name','middle_name','last_name', 'username', 'phone', 'email', 'sex', 'salutation','user_type_id','password_hash', 'is_blocked', 'user_type_id', 'created_at', 'nida'];
        $scenarios['update'] = ['first_name','middle_name','last_name', 'username', 'phone', 'email', 'sex', 'salutation', 'user_type_id', 'nida'];
        $scenarios['activation'] = ['password_hash','password_confirmation'];
        $scenarios['student_update'] = ['phone', 'email', 'photo', 'sex', 'birth_date', 'nida'];
        $scenarios['edit_student_details'] = ['first_name','middle_name','last_name','phone','email','sex','birth_date','nationality', 'nida'];
        $scenarios['upload'] = ['photo', 'photo_size', 'imageFile']; // Added imageFile to upload scenario
        $scenarios['min_student_update'] = ['email','phone'];
        $scenarios['verify'] = ['photo_verified', 'photo_verified_date'];
        $scenarios['nida_update'] = ['nida']; // Specific scenario for NIDA updates

        return $scenarios;
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getMySalutation()
    {
        return $this->hasOne(TblSalutation::className(), ['salutation' => 'id']);
    }

   /**
     * @return \yii\db\ActiveQuery
     */
    public function getTblPasswordBlacklisteds()
    {
        return $this->hasMany(TblPasswordBlacklisted::className(), ['users_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTblResultsCaHistories()
    {
        return $this->hasMany(TblResultsCaHistory::className(), ['users_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTblResultsUeHistories()
    {
        return $this->hasMany(TblResultsUeHistory::className(), ['users_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTblStaff()
    {
        return $this->hasOne(TblStaff::className(), ['users_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTblStudents()
    {
        return $this->hasMany(TblStudent::className(), ['users_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTblStudentBillings()
    {
        return $this->hasMany(TblStudentBilling::className(), ['user_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTblUploadHistories()
    {
        return $this->hasMany(TblUploadHistory::className(), ['users_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getUserType()
    {
        return $this->hasOne(TblUserType::className(), ['id' => 'user_type_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getNation()
    {
        return $this->hasOne(TblNationality::className(), ['id' => 'nationality']);
    }

    /**
     * Custom validation for NIDA format (Tanzanian specific)
     */
    public function validateNida($attribute, $params)
    {
        if (!empty($this->$attribute)) {
            // Tanzanian NIDA validation logic - only validate if not empty
            if (!preg_match('/^[0-9]{16,20}$/', $this->$attribute)) {
                $this->addError($attribute, 'NIDA number must contain 16-20 digits only');
            }
            
            // You can add more specific validation here
            // For example: checksum validation, specific prefix validation, etc.
        }
    }

    /**
     * Find user by NIDA number
     */
    public static function findByNida($nida)
    {
        if (empty($nida)) {
            return null;
        }
        return static::findOne(['nida' => $nida]);
    }

    /**
     * Check if NIDA number already exists
     */
    public function isNidaUnique($nida = null)
    {
        $nida = $nida ?: $this->nida;
        if (empty($nida)) {
            return true; // Empty is always considered unique
        }
        
        $exists = static::find()
            ->where(['nida' => $nida])
            ->andWhere(['!=', 'id', $this->id])
            ->exists();
            
        return !$exists;
    }

    /**
     * Check if user has NIDA number
     */
    public function hasNida()
    {
        return !empty($this->nida);
    }
    
    // users 
public function isPasswordInHistory($newPassword)
{
    $histories = PasswordHistory::find()
        ->where(['user_id' => $this->id])
        ->orderBy(['created_at' => SORT_DESC])
        ->limit(5)
        ->all();

    foreach ($histories as $history) {
        if (Yii::$app->security->validatePassword($newPassword, $history->password_hash)) {
            return true;
        }
    }

    return false;
}

public function savePasswordHistory()
{
    $history = new PasswordHistory();
    $history->user_id = $this->id;
    $history->password_hash = $this->password_hash;
    $history->save(false);

    // Keep only the latest 5 passwords
    $idsToDelete = PasswordHistory::find()
        ->select('id')
        ->where(['user_id' => $this->id])
        ->orderBy(['created_at' => SORT_DESC])
        ->offset(5)
        ->column();

    if (!empty($idsToDelete)) {
        PasswordHistory::deleteAll(['id' => $idsToDelete]);
    }
}

public function mustChangePassword()
{
    // 1. Admin forced reset (highest priority)
    if ($this->force_password_change == 1) {
        return true;
    }

    // 2. First login (no password ever set)
    if (empty($this->last_password_update)) {
        return true;
    }

    // 3. Expiry check (ONLY ONE SOURCE OF TRUTH)
    $expiryDate = strtotime($this->last_password_update . ' +90 days');

    if (time() >= $expiryDate) {
        return true;
    }

    // 4. Otherwise allow access
    return false;
}

    // ============================================
    // 🔐 FILE UPLOAD HELPER METHODS
    // ============================================

    /**
     * Upload photo with comprehensive security validation
     */
    public function uploadPhoto()
    {
        // Get the uploaded file instance
        $this->imageFile = UploadedFile::getInstance($this, 'imageFile');
        
        if (!$this->imageFile) {
            $this->addError('imageFile', 'No file selected.');
            return false;
        }

        // Validate the file using Yii2 validation
        if (!$this->validate(['imageFile'])) {
            return false;
        }

        // Additional server-side security checks
        $ext = strtolower($this->imageFile->extension);
        $mime = mime_content_type($this->imageFile->tempName);
        
        // Check for double extensions (security bypass)
        $filenameParts = explode('.', $this->imageFile->name);
        if (count($filenameParts) > 2) {
            $this->addError('imageFile', 'Invalid file name format.');
            return false;
        }

        // Verify actual image content using GD
        $imageInfo = getimagesize($this->imageFile->tempName);
        if ($imageInfo === false) {
            $this->addError('imageFile', 'Invalid image file. The file is corrupted or not a valid image.');
            return false;
        }

        // Verify MIME matches actual image type
        $imageMime = $imageInfo['mime'];
        if ($imageMime !== $mime) {
            $this->addError('imageFile', 'File type mismatch. Security validation failed.');
            return false;
        }

        // Check image dimensions
        $minWidth = 100;
        $minHeight = 100;
        $maxWidth = 4000;
        $maxHeight = 4000;
        
        if ($imageInfo[0] < $minWidth || $imageInfo[1] < $minHeight) {
            $this->addError('imageFile', "Image dimensions too small. Minimum: {$minWidth}x{$minHeight} pixels.");
            return false;
        }
        
        if ($imageInfo[0] > $maxWidth || $imageInfo[1] > $maxHeight) {
            $this->addError('imageFile', "Image dimensions too large. Maximum: {$maxWidth}x{$maxHeight} pixels.");
            return false;
        }

        // Generate secure filename
        $secureFilename = Yii::$app->security->generateRandomString(32) . '_' . time() . '.' . $ext;
        
        // Ensure upload directory exists
        $uploadPath = Yii::getAlias('@webroot') . '/uploads/photos/';
        if (!is_dir($uploadPath)) {
            if (!mkdir($uploadPath, 0755, true)) {
                $this->addError('imageFile', 'Failed to create upload directory.');
                return false;
            }
        }

        // Check directory is writable
        if (!is_writable($uploadPath)) {
            $this->addError('imageFile', 'Upload directory is not writable.');
            return false;
        }

        // Save file
        $filePath = $uploadPath . $secureFilename;
        
        if ($this->imageFile->saveAs($filePath)) {
            // Verify file was saved correctly
            if (!file_exists($filePath) || filesize($filePath) === 0) {
                $this->addError('imageFile', 'File was not saved correctly.');
                return false;
            }
            
            // Delete old photo if exists
            if (!empty($this->photo)) {
                $oldFilePath = Yii::getAlias('@webroot') . '/' . $this->photo;
                if (file_exists($oldFilePath) && strpos($oldFilePath, 'uploads/photos/') !== false) {
                    unlink($oldFilePath);
                }
            }
            
            // Update model attributes
            $this->photo = 'uploads/photos/' . $secureFilename;
            $this->photo_size = $this->imageFile->size;
            
            return true;
        }
        
        $this->addError('imageFile', 'Failed to upload photo.');
        return false;
    }

    /**
     * Get the full URL of the photo
     */
    public function getPhotoUrl()
    {
        if (!empty($this->photo) && file_exists(Yii::getAlias('@webroot') . '/' . $this->photo)) {
            return Yii::$app->request->baseUrl . '/' . $this->photo;
        }
        return Yii::$app->request->baseUrl . '/uploads/photos/default.jpg';
    }

    /**
     * Get photo size in human readable format
     */
    public function getPhotoSizeFormatted()
    {
        if ($this->photo_size) {
            return $this->formatFileSize($this->photo_size);
        }
        return 'N/A';
    }

    /**
     * Format file size
     */
    private function formatFileSize($bytes)
    {
        if ($bytes >= 1073741824) {
            return number_format($bytes / 1073741824, 2) . ' GB';
        } elseif ($bytes >= 1048576) {
            return number_format($bytes / 1048576, 2) . ' MB';
        } elseif ($bytes >= 1024) {
            return number_format($bytes / 1024, 2) . ' KB';
        } elseif ($bytes > 1) {
            return $bytes . ' bytes';
        } elseif ($bytes == 1) {
            return '1 byte';
        } else {
            return '0 bytes';
        }
    }

    /**
     * Delete user photo
     */
    public function deletePhoto()
    {
        if (!empty($this->photo)) {
            $filePath = Yii::getAlias('@webroot') . '/' . $this->photo;
            if (file_exists($filePath) && strpos($filePath, 'uploads/photos/') !== false) {
                if (unlink($filePath)) {
                    $this->photo = null;
                    $this->photo_size = null;
                    $this->save(false);
                    return true;
                }
            }
        }
        return false;
    }

    //AUDIT TRAILS TRACKER
    // public function behaviors()
    // {
    //     return [
    //         'bedezign\yii2\audit\AuditTrailBehavior'
    //     ];
    // }
}