<?php
/********************************************************************************
 * (c)1337 aheadware.com - All rights reserved
 ********************************************************************************/

/**
 * Class TB_Shared_Ent_TeamData_Profile
 *
 * @property integer $id
 * @property integer $account_id
 * @property string $public_id
 * @property string|null $pic_url
 * @property string|null $pic_cloud_id
 * @property string|null $status
 * @property string $gender
 * @property string|null $first_name
 * @property string|null $last_name
 * @property Date|null $birthday_dt
 * @property string|null $street
 * @property string|null $zip_code
 * @property string|null $city
 * @property string|null $country
 * @property string|null $phone
 * @property string|null $mobile
 * @property string|null $misc
 * @property array|null $teams_js
 * @property array|null $team_prop_js
 * @property array|null $team_category_ids_js
 * @property array|null $manager_access_ids_js
 * @property array|null $child_profile_js
 * @property DateTime $last_updated_dt
 * @property DateTime $created_dt
 */
class TB_Shared_Ent_TeamData_Profile extends Francis_Db_Row {

    const ROLE_TRAINER = 'trainer';
    const ROLE_COTRAINER = 'cotrainer';
    const ROLE_PLAYER = 'player';

    // Enums
    const GENDER_MALE = 'male';
    const GENDER_FEMALE = 'female';

    const VISIBILITY_PUBLIC = 'public';
    const VISIBILITY_PRIVATE = 'private';

    /**
     * Return valid gender values
     *
     * @return array
     */
    public static function getValidGender() {
        return array(
            self::GENDER_MALE,
            self::GENDER_FEMALE
        );
    }

    public static function getValidRoles()
    {
        return array(
            self::ROLE_PLAYER,
            self::ROLE_COTRAINER,
            self::ROLE_TRAINER
        );
    }

    /**
     * Get first profile by account id
     * @param $accountId
     * @return array
     */
    public static function getByAccountId( $accountId ) {
        $sql = 'SELECT * FROM ' . self::getTable() . ' WHERE account_id = :account_id';
        $params = array( ':account_id' => $accountId );
        return self::findOne( $sql, $params );
    }

    /**
     * Get by public id
     * @param $publicId
     * @return array
     */
    public static function getByPublicId( $publicId ) {
        $sql = 'SELECT * FROM ' . self::getTable() . ' WHERE public_id = :public_id';
        $params = array( ':public_id' => $publicId );
        return self::findOne( $sql, $params );
    }

    public static function getByCourseCategoryId( $courseCategoryId )
    {
        $whereJson = json_encode( array( $courseCategoryId ) );
        $sql = 'SELECT * FROM ' . self::getTable() . ' WHERE ';
        $sql .= 'JSON_CONTAINS( `team_category_ids_js`, :where_json ) ';

        $params = array( ':where_json' => $whereJson );
        return self::findMany( $sql, $params );
    }


    /**
     * Return table name
     *
     * @return null|string
     */
    public static function getTable() {
        return 'profile';
    }

    /**
     * Return db handler
     *
     * @return Francis_Db_MySql|null
     */
    public static function getDbh() {
        return TB_Shared_Db_TeamData::get();
    }

    public static function resolveDisplayNameByEmail( $email ) {
        $name = NULL;
        if ( TB_Shared_Utils_Validator::isValidEmail( $email ) ) {
            $parts = explode( "@", $email );
            if ( 0  < count( $parts ) ) {
                $name = $parts[0];
            }
        }
        return $name;
    }

    public static function getTodaysBirthdayProfiles()
    {
        $sql = "SELECT * FROM " . self::getTable() . " ";
        $sql .= "WHERE DATE_FORMAT(birthday_dt,'%m-%d') = DATE_FORMAT(NOW(),'%m-%d')";

        return self::findMany( $sql );
    }

    /**
     * Get timestamp ids
     *
     * @return NULL|TB_Shared_Ent_TeamData_ProfileTimestamp
     */
    public function getTimestamps() {
        return TB_Shared_Ent_TeamData_ProfileTimestamp::getByProfileId( $this->id );
    }

    /**
     * Get first + last name
     * @return string
     */
    public function getName() {
        $name = 'Unknown';
        if ( is_string( $this->first_name ) && 0 < mb_strlen( $this->first_name ) )
        {
            $name = $this->first_name;

            if ( is_string( $this->last_name ) && 0 < mb_strlen( $this->last_name ) )
            {
                $name = $name . ' ' . $this->last_name;
            }
        }
        else if ( is_string( $this->last_name ) && 0 < mb_strlen( $this->last_name ) )
        {
            $name = $this->last_name;
        }
        return $name;
    }

    /**
     * Anonymize profile
     */
    public function anonymize()
    {
        $this->account_id = NULL;
        $this->public_id = NULL;
        $this->pic_url = NULL;
        $this->pic_cloud_id = NULL;
        $this->first_name = NULL;
        $this->last_name = NULL;
        $this->birthday_dt = NULL;
        $this->street = NULL;
        $this->zip_code = NULL;
        $this->city = NULL;
        $this->phone = NULL;
        $this->mobile = NULL;
        $this->misc = NULL;
    }

    public function anonymizeAddressData()
    {
        $this->birthday_dt = NULL;
        $this->street = NULL;
        $this->zip_code = NULL;
        $this->city = NULL;
        $this->phone = NULL;
        $this->mobile = NULL;
    }

    /**
     * Called during deletion
     */
    public function deleteReferences()
    {
        // Delete image from cloud
        if ( !is_null( $this->pic_cloud_id ) )
        {
            $cloudinary = TB_Server_Utils_Cloudinary::get();
            $cloudinary->delete( $this->pic_cloud_id );
        }

        // Delete teamdata related entries
        TB_Shared_Ent_TeamData_Attendee::deleteAllForProfileId( $this->id );
        TB_Shared_Ent_TeamData_ProfileTimestamp::deleteAllForProfileId( $this->id );
        TB_Shared_Ent_TeamData_Chat::deleteByAuthorProfileId( $this->id );
        TB_Shared_Ent_TeamData_Notification::deleteByAuthorProfileId( $this->id );
        TB_Shared_Ent_TeamData_Notification::deleteByReceiverProfileId( $this->id );
        // @todo Add message deletion as soon as messages are active


    }

    /**
     * @param $teamId
     * @return mixed|null
     */
    public function getTeamsData( $teamId )
    {
        $ret = NULL;
        if ( is_array( $this->teams_js ) )
        {
            foreach( $this->teams_js as $teamData )
            {
                if ( $teamData[ 'team_id' ] == $teamId )
                {
                    $ret = $teamData;
                    break;
                }
            }
        }
        return $ret;
    }

    /**
     * @return array
     */
    public function getTeamIds()
    {
        $teamIds = array();

        if ( is_array( $this->teams_js ) )
        {
            foreach( $this->teams_js as $teamData )
            {
                array_push( $teamIds, $teamData[ 'team_id' ] );
            }
        }

        return $teamIds;
    }

    /**
     * @param $teamId
     * @return bool
     */
    public function isInTeam( $teamId )
    {
        $teamData = $this->getTeamsData( $teamId );
        return ( is_array(  $teamData ) );
    }

    /**
     * @param $teamId
     * @return bool
     */
    public function isAdminOfTeam( $teamId )
    {
        $isAdmin = false;

        $td = $this->getTeamsData( $teamId );
        if ( is_array( $td ) )
        {
            $isAdmin = ( $td[ 'role' ] == self::ROLE_COTRAINER || $td[ 'role' ] == self::ROLE_TRAINER ) ? true : false;
        }

        return $isAdmin;
    }

    public function isManagerAccessAllowed( $teamId )
    {
        $isAccessAllowed = false;

        if ( $this->isOwnerOfTeam( $teamId ) )
        {
            $isAccessAllowed = true;
        }
        else if ( is_array( $this->manager_access_ids_js ) )
        {
            $isAccessAllowed = in_array( +$teamId, $this->manager_access_ids_js );
        }

        return $isAccessAllowed;
    }

    /**
     * @param $teamId
     * @return bool
     */
    public function isOwnerOfTeam ( $teamId )
    {
        $isOwner = false;

        $td = $this->getTeamsData( $teamId );
        if ( is_array( $td ) )
        {
            $isOwner = ( $td[ 'role' ] == self::ROLE_TRAINER ) ? true : false;
        }

        return $isOwner;
    }

    /**
     * @return bool
     */
    public function ownsATeam()
    {
        $isOwner = false;

        foreach( $this->teams_js as $td )
        {
            if ( $td [ 'role' ] == self::ROLE_TRAINER )
            {
                $isOwner = true;
                break;
            }
        }

        return $isOwner;
    }

    /**
     * @param $teamId
     * @return mixed|null
     */
    public function getRoleInTeam( $teamId )
    {
        $role = NULL;

        $td = $this->getTeamsData( $teamId );
        if ( is_array( $td ) )
        {
            $role = $td[ 'role' ];
        }

        return $role;
    }

    /**
     * @param $teamId
     * @param $role
     */
    public function setRoleInTeam( $teamId, $role )
    {
        if ( !in_array( $role, self::getValidRoles() ) )
        {
            throw new \Exception( "Invalid role to set: " . $role );
        }

        $profileTeamData = array();
        if ( is_array( $this->teams_js ) )
        {
            // Make a copy
            $profileTeamData = unserialize( serialize( $this->teams_js ) );
        }


        foreach( $profileTeamData as &$teamData )
        {
            if ( $teamId === $teamData[ 'team_id' ] )
            {
                $teamData[ 'role' ] = $role;

                // By default ADMINs cannot be anonymous
                if ( $role === self::ROLE_TRAINER || $role === self::ROLE_COTRAINER )
                {
                    $teamData[ 'is_anonymous' ] = 0;
                }
                break;
            }
        }

        $this->teams_js = $profileTeamData;
    }

    /**
     * @param $teamId
     * @param $contract
     */
    public function setContractInTeam( $teamId, $contract, $contractDate )
    {
        $profileTeamData = array();
        if ( is_array( $this->teams_js ) )
        {
            // Make a copy
            $profileTeamData = unserialize( serialize( $this->teams_js ) );
        }


        foreach( $profileTeamData as &$teamData )
        {
            if ( $teamId === $teamData[ 'team_id' ] )
            {
                $teamData[ 'contract' ] = $contract;
                $teamData[ 'contract_date' ] = $contractDate;
                break;
            }
        }

        $this->teams_js = $profileTeamData;
    }

    /**
     * @param $teamId
     */
    public function joinTeam( $teamId )
    {
        // Note: right now - all joins are with role PLAYER only
        $role = TB_Shared_Ent_TeamData_Profile::ROLE_PLAYER;

        if ( $this->isInTeam( $teamId ) )
        {
            return;
        }

        $teamsJson = $this->teams_js;
        if ( !is_array( $teamsJson ) )
        {
            $teamsJson = array();
        }
        array_push( $teamsJson, array(
            'team_id' => $teamId,
            'role' => TB_Shared_Ent_TeamData_Profile::ROLE_PLAYER,
            'is_anonymous' => 0,
            'join_dt' => TB_Server_Utils_Helper::getUTCNowDateTime()
        ));

        $this->teams_js = $teamsJson;
    }

    /**
     * @param $teamId
     */
    public function leaveTeam( $teamId )
    {
        if ( false === $this->isInTeam( $teamId ) )
        {
            return;
        }

        $teamJson = array();
        foreach( $this->teams_js as $teamData )
        {
            if ( $teamData[ 'team_id' ] == $teamId )
            {
                continue;
            }
            else
            {
                array_push( $teamJson, $teamData );
            }
        }

        $this->teams_js = $teamJson;

        if ( is_array( $this->team_category_ids_js ) )
        {
            $teamCategoryIds = array();
            $teamCategoryPrefix = $teamId . '-';

            foreach( $this->team_category_ids_js as $tcid )
            {
                if ( strpos( $tcid, $teamCategoryPrefix ) )
                {
                    array_push( $teamCategoryIds, $tcid );
                }
            }

            $this->team_category_ids_js = $teamCategoryIds;
        }
    }


    /**
     * @param $teamId
     * @param $isAnonymous
     * @throws Exception
     */
    public function setAnonymousStateInTeam( $teamId, $isAnonymous )
    {
        if ( $isAnonymous != "0" && $isAnonymous != "1" )
        {
            throw new \Exception( "Invalid value for isAnonymous: " . $isAnonymous );
        }

        $profileTeamData = array();
        if ( is_array( $this->teams_js ) )
        {
            $profileTeamData = unserialize( serialize( $this->teams_js ) );
        }

        foreach( $profileTeamData as &$teamData )
        {
            if ( $teamId === $teamData[ 'team_id' ] )
            {
                $teamData[ 'is_anonymous' ] = $isAnonymous;
                break;
            }
        }

        $this->teams_js = $profileTeamData;
    }

    /**
     * @param $teamId
     * @return bool|mixed
     */
    public function isAnonymousInTeam( $teamId )
    {
        $isAnonymous = false;
        $td = $this->getTeamsData( $teamId );
        if ( is_array( $td ) )
        {
            $isAnonymous = ( $td[ 'is_anonymous' ] == 1 ) ? true : false;
        }
        return $isAnonymous;
    }

    public function addToCategoryId( $categoryId )
    {
        $profileCategories = $this->team_category_ids_js;

        if ( !is_array( $profileCategories ) )
        {
            $profileCategories = array();
        }

        if ( !in_array( $categoryId, $profileCategories ) )
        {
            array_push( $profileCategories, $categoryId );
            $this->team_category_ids_js = $profileCategories;
            return true;
        }
        else
        {
            return false;
        }
    }

    public function removeCategoryId( $categoryId )
    {
        if ( !is_array( $this->team_category_ids_js ) )
        {
            return false;
        }

        if ( in_array( $categoryId, $this->team_category_ids_js ) )
        {
            $this->team_category_ids_js = array_diff( $this->team_category_ids_js, array( $categoryId ) );
            return true;
        }
        else
        {
            return false;
        }
    }

    public function hasCategoryId( $categoryId )
    {
        if ( !is_array( $this->team_category_ids_js ) )
        {
            return false;
        }

        return ( in_array( $categoryId, $this->team_category_ids_js ) );
    }

    /**
     * @param TB_Shared_Ent_TeamData_Profile $profile
     * @return bool
     */
    public function isOwnProfile( TB_Shared_Ent_TeamData_Profile $profile )
    {
        return ( $this->id == $profile->id );
    }

    public function canAccessProfile( TB_Shared_Ent_TeamData_Profile $profile )
    {
        // If it is own profile
        if ( $this->id == $profile->id ) return true;

        $canAccess = false;
        $teamIds = array_intersect( $this->getTeamIds(), $profile->getTeamIds() );

        if ( 0 < count( $teamIds ) )
        {
            foreach( $teamIds as $teamId )
            {
                if ( $this->isAdminOfTeam( $teamId ) )
                {
                    $canAccess = true;
                    break;
                }

                if ( false === $profile->isAnonymousInTeam( $teamId ) )
                {
                    $canAccess = true;
                    break;
                }
            }
        }

        return $canAccess;
    }

    public function canAdministrateProfile( TB_Shared_Ent_TeamData_Profile $profile )
    {
        // If it is own profile
        if ( $this->id == $profile->id ) return true;

        $isAdminOfTeam = false;
        $teamIds = array_intersect( $this->getTeamIds(), $profile->getTeamIds() );

        if ( 0 < count( $teamIds ) )
        {
            foreach( $teamIds as $teamId )
            {
                if ( $this->isAdminOfTeam( $teamId ) )
                {
                    $isAdminOfTeam = true;
                    break;
                }
            }
        }

        return $isAdminOfTeam;
    }


    public function getAge()
    {
        $age = NULL;
        if ( $this->birthday_dt )
        {
            $nowDt = new DateTime();
            $nowDt->setTime( 23, 59, 59 );
            $age = $nowDt->diff( $this->birthday_dt )->y;
        }
        return $age;
    }

    public function getChildById( $childId )
    {
        $child = NULL;
        if ( $this->child_profile_js && count( $this->child_profile_js ) > 0 )
        {
            foreach( $this->child_profile_js as $cp )
            {
                if ( $cp[ 'id' ] == $childId )
                {
                    $child = $cp;
                    break;
                }
            }
        }
        return $child;
    }

    public function hasChild( $childId )
    {
        return ( NULL !== $this->getChildById( $childId ) );
    }

    /**
     * @param $teamId
     * @return array
     */
    public static function getProfilesByTeamId( $teamId )
    {
        $whereJson = json_encode( array( 'team_id' => $teamId ) );
        $sql = 'SELECT * FROM ' . self::getTable() . ' WHERE ';
        $sql .= 'JSON_CONTAINS( `teams_js`, :where_json ) ';
        $sql .= 'ORDER BY last_name ASC';

        $params = array( ':where_json' => $whereJson );
        return self::findMany( $sql, $params );
    }

    public static function getNumProfilesByTeamId( $teamId )
    {
        $dbh = self::getDbh();
        $whereJson = json_encode( array( 'team_id' => $teamId ) );
        $sql = 'SELECT COUNT( id ) AS cnt_num FROM ' . self::getTable() . ' WHERE ';
        $sql .= 'JSON_CONTAINS( `teams_js`, :where_json ) ';
        $stmt = $dbh->prepare( $sql );
        $stmt->execute( array( ':where_json' => $whereJson ) );
        $params = array( ':where_json' => $whereJson );
        $res = $stmt->fetch( PDO::FETCH_COLUMN );
        return $res;
    }

    public static function getProfilesByRole( $role )
    {
        $whereJson = json_encode( array( 'role' => $role ) );
        $sql = 'SELECT * FROM ' . self::getTable() . ' WHERE ';
        $sql .= 'JSON_CONTAINS( `teams_js`, :where_json ) ';

        $params = array( ':where_json' => $whereJson );
        return self::findMany( $sql, $params );
    }

    /**
     * @param $teamId
     * @return array
     */
    public static function getAdminsOfTeamId( $teamId )
    {
        $admins = array();
        $members = self::getProfilesByTeamId( $teamId );
        /** @var TB_Shared_Ent_TeamData_Profile $member */
        foreach( $members as $member )
        {
            if ( $member->isAdminOfTeam( $teamId ) )
            {
                array_push( $admins, $member );
            }
        }
        return $admins;
    }



    /**
     * @param array $profileIds
     * @return array
     */
    public static function getAccountIdOfProfileIds( array $profileIds )
    {
        $accountIds = array();
        if ( 0 === count( $profileIds ) ) return $accountIds;

        $dbh = TB_Shared_Ent_TeamData_Profile::getDbh();
        $in  = str_repeat('?,', count( $profileIds ) - 1) . '?';
        $sql = "SELECT account_id FROM " . TB_Shared_Ent_TeamData_Profile::getTable() . " WHERE id IN ($in)";
        $stmt = $dbh->prepare( $sql );
        $stmt->execute( $profileIds );
        $accountIds = $stmt->fetchAll( PDO::FETCH_COLUMN, 0 );

        return $accountIds;
    }
}