<?php

/**
 * Class TB_Server_Control_Contract
 */
class TB_Server_Control_Contract
{

    /**
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     * @throws Exception
     */
    public static function getOverview( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $teamId = $params->get( 'teamId' );
        if ( false === $sessionProfile->isAdminOfTeam( $teamId ) )
        {
            throw new \Exception( 'Profile is not allowed to get overview' );
        }

        $entCs = TB_Shared_Ent_TeamData_Contract::getForOverview( $teamId );

        $last30days = array();

        for (  $i = 0; $i < 30; $i++ )
        {
            $day = date('Y-m-d', strtotime( "-$i day" ) );
            $cntCreated = 0;
            $cntExpired = 0;
            $cntBegun = 0;

            /** @var TB_Shared_Ent_TeamData_Contract $entC */
            foreach( $entCs as $entC )
            {
                if ( $entC->start_date === $day )
                {
                    $cntBegun++;
                }

                if ( $entC->end_date === $day )
                {
                    $cntExpired++;
                }

                if ( $entC->created_dt->format( 'Y-m-d' ) === $day )
                {
                    $cntCreated++;
                }
            }

            $stat = array(
                'day' => $day,
                'num_created' => $cntCreated,
                'num_expired' => $cntExpired,
                'num_begun' => $cntBegun
            );
            array_push( $last30days, $stat );
        }

        $last30days = array_reverse( $last30days );

        $stats = array(
            'num_contracts_total' => TB_Shared_Ent_TeamData_Contract::getCountForTeamId( $teamId ),
            'num_contracts_open' => TB_Shared_Ent_TeamData_Contract::getCountOpenForTeamId( $teamId ),
            'open_payments' => TB_Shared_Ent_TeamData_Contract::getSumOpenPaymentsForTeamId( $teamId ),
            'num_appointments_to_charge' => TB_Shared_Ent_TeamData_Contract::getCountOpenAttendancesToChargeForTeamId( $teamId ),
            'last_30_days' => $last30days,
        );

        $resp->addData( 'stats', $stats );
        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     * @throws Exception
     */
    public static function getList( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $teamId = $params->get('teamId');
        $profileId = $params->get( 'profileId' );
        $state = $params->get( 'state' );
        $filter = $params->get( 'filter' );
        if ( false === $sessionProfile->isAdminOfTeam( $teamId ) )
        {
            throw new \Exception('Profile is not allowed to get contract list');
        }

        if ( NULL === $filter )
        {
            $resp->addRowsToData( 'contractData', TB_Shared_Ent_TeamData_Contract::getAllForTeamId( $teamId, $profileId, $state ) );
        }
        else
        {
            if ( $filter === 'claim' )
            {
                $resp->addRowsToData( 'contractData', TB_Shared_Ent_TeamData_Contract::getAllForTeamIdWithOpenClaims( $teamId ) );
            }
        }

        return $resp;
    }

    public static function getAll( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();

        $resp->addRowsToData( 'contractData', TB_Shared_Ent_TeamData_Contract::getAllForProfileId( $sessionProfile->id ) );

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     * @throws Exception
     */
    public static function getDetail( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $contractId = $params->get('contractId' );
        $contract = TB_Shared_Ent_TeamData_Contract::get( $contractId );
        if ( NULL === $contract )
        {
            throw new \Exception( 'Contract not found.' );
        }

        if ( false === $sessionProfile->isAdminOfTeam( $contract->team_id ) && $sessionProfile->id != $contract->profile_id )
        {
            throw new \Exception('Profile is not allowed to get contract list');
        }

        $resp->addData( 'contractData', $contract->asArray() );
        if ( $contractId > 0 )
        {
            $resp->addData( 'contractAppointments', TB_Shared_Ent_TeamData_Appointment::getAssignedForContractId( $contractId ) );
        }
        else
        {
            $resp->addData( 'contractAppointments', [] );
        }

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     * @throws Exception
     */
    public static function getUnchargedProfileIds(TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $teamId = $params->get('teamId');
        if ( false === $sessionProfile->isAdminOfTeam( $teamId ) )
        {
            throw new \Exception('Profile is not allowed to get contract list');
        }

        $resp->addData(
            'unchargedProfileIds',
            TB_Shared_Ent_TeamData_Contract::getUnchargedProfileIdsForTeam( $teamId )
        );

        return $resp;
    }

    /**
     * @param TB_Server_Core_RequestData $params
     * @return TB_Server_Core_Response
     * @throws Exception
     */
    public static function create( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $teamId = $params->get('team_id');
        if ( false === $sessionProfile->isAdminOfTeam( $teamId ) )
        {
            throw new \Exception('Profile is not allowed to create contract');
        }

        $team = TB_Shared_Ent_TeamData_Team::get( $teamId );
        if ( !$team )
        {
            throw new \Exception( 'Team does not exists anymore.' );
        }

        // Validation

        $profile = TB_Shared_Ent_TeamData_Profile::get( $params->get( 'profile_id' ) );

        if ( NULL === $profile )
        {
            throw new \Exception( 'Contract profile not found.' );
        }

        $name = $params->get( 'name' );
        if ( empty(  $name ) )
        {
            throw new \Exception( 'Invalid name value for contract.' );
        }

        $type = $params->get( 'type' );
        if ( $type !== 'flatrate' && $type !== 'quota' )
        {
            throw new \Exception( 'Invalid type value for contract.' );
        }

        $maxPriceFactor = NULL;
        if ( $type === 'quota' )
        {
            $maxPriceFactor = +$params->get( 'max_price_factor', 0 );
            if ( $maxPriceFactor <= 0 )
            {
                throw new \Exception( 'Invalid max price factor for contract: ' . $maxPriceFactor );
            }
        }

        $currency = $params->get( 'currency' );
        if ( $currency !== 'EUR' && $currency !== 'CHF' )
        {
            throw new \Exception( 'Invalid currency value: ' . $currency );
        }

        $price = +$params->get( 'price', 0 );
        /*
        if ( $price <= 0 )
        {
            throw new \Exception( 'Invalid price for contract.' );
        }
        */

        $startDate = $params->get( 'start_date' );
        $endDate = $params->get( 'end_date' );
        $paymentDueDate = $params->get( 'payment_due_date' );

        $adminNote = $params->get( 'admin_note' );
        if ( $adminNote && 0 === mb_strlen( $adminNote ) )
        {
            $adminNote = NULL;
        }

        $cmd = $team->contractee_master_data_js;
        $cName = array_key_exists( 'name', $cmd) ? $cmd[ 'name' ] : NULL;
        $cStreet = array_key_exists( 'street', $cmd ) ? $cmd[ 'street' ] : NULL;
        $cZipCode = array_key_exists( 'zip_code', $cmd ) ? $cmd[ 'zip_code' ] : NULL;
        $cCity = array_key_exists( 'city', $cmd ) ? $cmd[ 'city' ] : NULL;
        $cCountry = array_key_exists( 'country', $cmd ) ? $cmd[ 'country' ] : NULL;

        if ( !$cName || !$cStreet || !$cZipCode || !$cCity || !$cCountry )
        {
            throw new \Exception( 'Invalid contractee data.' );
        }

        $contract = new TB_Shared_Ent_TeamData_Contract();
        $contract->team_id = $teamId;
        $contract->contractee_data_js = array(
            'groupName' => $team->display_name,
            'name' => $cName,
            'street' => $cStreet,
            'zip_code' => $cZipCode,
            'city' => $cCity,
            'country' => $cCountry
        );
        $contract->profile_id = $profile->id;
        $contract->profile_data_js = array(
            'gender' => $profile->gender,
            'first_name' => $profile->first_name,
            'last_name' => $profile->last_name,
            'street' => $params->get( 'street' ),
            'zip_code' => $params->get( 'zip_code' ),
            'city' => $params->get( 'city' ),
            'country' => $params->get( 'country' )
        );
        $contract->name = $name;
        $contract->type = $type;
        $contract->max_price_factor = $maxPriceFactor;
        $contract->currency = $currency;
        $contract->price = $price;
        $contract->start_date = $startDate;
        $contract->end_date = $endDate;
        $contract->payment_due_date = $paymentDueDate;
        $contract->admin_note = $adminNote;

        $contract->save();

        $resp->addData( 'contract', $contract );

        return $resp;
    }

    public static function batchDelete( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $contractIds = $params->get('contractIds' );


        $db  = TB_Shared_Db_TeamData::get();
        try
        {
            $db->beginTransaction();

            foreach( $contractIds as $contractId )
            {
                $contract = TB_Shared_Ent_TeamData_Contract::get( $contractId );

                if ( false === $sessionProfile->isAdminOfTeam( $contract->team_id ) ||
                    $contract->state !== 'archive' )
                {
                    continue;
                }

                $contract->delete();
            }

            $db->commit();

        }
        catch( Exception $ex )
        {
            $db->rollBack();
            throw $ex;
        }

        return $resp;
    }

    public static function batchArchiving( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $contractIds = $params->get('contractIds' );

        foreach( $contractIds as $contractId )
        {
            $contract = TB_Shared_Ent_TeamData_Contract::get( $contractId );

            if ( false === $sessionProfile->isAdminOfTeam( $contract->team_id ) )
            {
                continue;
            }

            $contract->state = 'archive';
            $contract->save();
        }

        return $resp;
    }

    public static function batchReactivate( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $contractIds = $params->get('contractIds' );

        foreach( $contractIds as $contractId )
        {
            $contract = TB_Shared_Ent_TeamData_Contract::get( $contractId );

            if ( false === $sessionProfile->isAdminOfTeam( $contract->team_id ) )
            {
                continue;
            }

            $contract->state = 'active';
            $contract->save();
        }

        return $resp;
    }

    public static function batchMarkPayed(  TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $contractIds = $params->get('contractIds' );

        foreach( $contractIds as $contractId )
        {
            $contract = TB_Shared_Ent_TeamData_Contract::get( $contractId );

            if ( false === $sessionProfile->isAdminOfTeam( $contract->team_id ) )
            {
                continue;
            }

            $contract->price_payed = $contract->price;
            $contract->save();
        }

        return $resp;
    }

    public static function update( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $contractId = +$params->get( 'id' );
        $contract = TB_Shared_Ent_TeamData_Contract::get( $contractId );

        if ( NULL === $contract )
        {
            throw new \Exception( 'Contract not found' );
        }

        if ( false === $sessionProfile->isAdminOfTeam( $contract->team_id ) )
        {
            throw new \Exception('Profile is not allowed to update contract');
        }

        $name = $params->get( 'name', $contract->name );
        if ( empty(  $name ) )
        {
            throw new \Exception( 'Invalid name value for contract.' );
        }

        $type = $params->get( 'type', $contract->type );
        if ( $type !== 'flatrate' && $type !== 'quota' )
        {
            throw new \Exception( 'Invalid type value for contract.' );
        }

        $maxPriceFactor = $contract->max_price_factor;
        $currentPriceFactor = $contract->current_price_factor;
        if ( $type === 'quota' )
        {
            $maxPriceFactor = +$params->get( 'max_price_factor', 0 );
            if ( $maxPriceFactor <= 0 )
            {
                throw new \Exception( 'Invalid max price factor for contract: ' . $maxPriceFactor );
            }
            /*
            $currentPriceFactor = +$params->get( 'current_price_factor', 0 );
            if ( $currentPriceFactor <= 0 )
            {
                throw new \Exception( 'Invalid current price factor for contract: ' . $currentPriceFactor );
            }
            */
        }

        $price = +$params->get( 'price', $contract->price );
        /*
        if ( $price < 0 )
        {
            throw new \Exception( 'Invalid price for contract.' );
        }
        */

        $pricePayed = +$params->get( 'price_payed', $contract->price_payed );
        /*
        if ( $pricePayed < 0 )
        {
            throw new \Exception( 'Invalid price payed for contract.' );
        }
        */

        $adminNote = $params->get( 'admin_note' );
        if ( $adminNote && 0 === mb_strlen( $adminNote ) )
        {
            $adminNote = NULL;
        }

        $startDate = $params->get( 'start_date' );
        $endDate = $params->get( 'end_date' );
        $paymentDueDate = $params->get( 'payment_due_date' );

        $profileData = array();
        if ( is_array( $contract->profile_data_js ) )
        {
            $profileData = unserialize( serialize( $contract->profile_data_js ) );
        }

        $contract->name = $name;
        $contract->type = $type;
        $contract->max_price_factor = $maxPriceFactor;
        //$contract->current_price_factor = $currentPriceFactor;
        $profileData[ 'street' ] = $params->get( 'street' );
        $profileData[ 'zip_code' ] = $params->get( 'zip_code' );
        $profileData[ 'city' ] = $params->get( 'city' );
        $profileData[ 'country' ] = $params->get( 'country' );
        $contract->profile_data_js = $profileData;
        $contract->price = $price;
        $contract->price_payed = $pricePayed;
        $contract->start_date = $startDate;
        $contract->end_date = $endDate;
        $contract->payment_due_date = $paymentDueDate;
        $contract->admin_note = $adminNote;

        $contract->save();

        $resp->addData( 'contract', $contract );

        return $resp;
    }

    public static function updateAttendances( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $teamId = $params->get( 'teamId' );
        $contractId = +$params->get( 'contractId' );
        $contract = TB_Shared_Ent_TeamData_Contract::get( $contractId );
        $profileId = $params->get( 'profileId' );
        $profile = TB_Shared_Ent_TeamData_Profile::get( $profileId );
        $attendancesIds = $params->get( 'attendancesIds' );

        // Note
        // -1 is a valid contract id for our dummy contract
        if ( 0 < $contractId && NULL === $contract )
        {
            throw new \Exception( 'Contract not found' );
        }

        if ( $contract && false === $sessionProfile->isAdminOfTeam( $contract->team_id ) )
        {
            throw new \Exception('Profile is not allowed to update contract');
        }

        if ( $contractId <= 0 && NULL === $profile )
        {
            throw new \Exception( 'Cannot update fake contract attendances without a valid profile' );
        }

        if ( !is_array( $attendancesIds ) )
        {
            throw new \Exception('Missing attendances ids.' );
        }

        TB_Shared_Ent_TeamData_Attendee::removeContractId( $contractId, $profileId, $teamId );

            // Set contract id to attendances
        foreach( $attendancesIds as $attendancesId )
        {
            /** @var TB_Shared_Ent_TeamData_Attendee $att */
            $att = TB_Shared_Ent_TeamData_Attendee::get( $attendancesId );
            $att->contract_id = $contractId;
            $att->save();
        }

        if ( $contract )
        {
            // Update current price factor
            TB_Shared_Ent_TeamData_Contract::updateCurrentPriceFactorByContractId( $contractId );
        }

        return $resp;
    }

    public static function activateTestphase( TB_Server_Core_RequestData $params )
    {
        $resp = new TB_Server_Core_Response();

        $sessionProfile = TB_Server_Core_Session::get()->getProfile();
        $sessionAccount = TB_Server_Core_Session::get()->getAccount();
        $teamId = $params->get( 'teamId' );
        $team = TB_Shared_Ent_TeamData_Team::get( $teamId );

        if ( false === $sessionProfile->isOwnerOfTeam( $teamId ) )
        {
            throw new \Exception( 'Only team owners can activate test phase.' );
        }

        $zContract = new TB_Shared_Ent_TeamData_ZContracts();
        $zContract->fk_publicTeamID = $team->public_id;
        $zContract->fk_TeamID = $team->id;
        $zContract->displayName = $team->display_name;
        $zContract->Invoice_number = NULL;
        $zContract->status = 'Test Vollversion';
        $zContract->status_visible = 'Lead';
        $zContract->product = 'ProBuddy';
        $zContract->product_volume = 50;
        $zContract->product_type = 'Vertrag';
        $now = TB_Server_Utils_Helper::getUTCNowDateTime();
        $zContract->create_dt = TB_Server_Utils_Helper::getUTCNowDateTime();
        $zContract->valid_from = $now->format( 'Y-m-d' );
        $now->add( new \DateInterval( 'P30D' ) );
        $zContract->valid_to = $now->format( 'Y-m-d' );
        $zContract->contracted_period = 12;
        $zContract->price_regularMonth = 19.90;
        $zContract->Invoice_firstName = $sessionProfile->first_name;
        $zContract->Invoice_lastName = $sessionProfile->last_name;
        $zContract->Invoice_street = NULL;
        $zContract->Invoice_town = NULL;
        $zContract->Invoice_PLZ = NULL;
        $zContract->invoice_country = NULL;
        $zContract->Invoice_eMail = $sessionAccount->email;
        $zContract->Invoice_website = NULL;

        $zContract->save();

        return $resp;
    }

}