<?php

use PHPUnit\Framework\TestCase;

class dropimageTest extends TestCase {

    /**
     * @throws NotFoundException
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws ServerException
     * @throws NotModifiedException
     */
    protected function setUp(): void {
        database::connect();
        try {
            session::init(new DummySession());
            session::becomeAdmin();
            $user = user::getFirstAdmin();
            session::set('user', $user);
            session::set('userId', $user['id']);
            session::refreshProjectPermissions();
            session::set('wwwRoot',realpath(__DIR__.'/../../../'));
        } catch (BadRequestException $e) {
            echo $e->getMessage();
            $this->fail('BadRequestException on session::init');
        } catch (NotFoundException) {
            $this->fail('NotFoundException on session::init');
        } catch (ServerException) {
            $this->fail('ServerException on session::init');
        }
        database::begin();
        $now=time();
        $sharedProject=project::getByName(baseproject::SHARED);
        $sharedProjectId=$sharedProject['id'];
        $defaultProject=project::getByName(baseproject::DEFAULTPROJECT);
        $defaultProjectId=$defaultProject['id'];
        $scoringSystemId=crystalscoringsystem::create(array('name'=>'SCORING_SYSTEM'.$now))['created']['id'];
        crystalscore::create(array(
            'crystalscoringsystemid'=>$scoringSystemId, 'color'=>'ff0000',
            'name'=>'TEST_Crystals','label'=>'Crystals','scoreindex'=>2,'hotkey'=>2)
        );
        crystalscore::create(array(
            'crystalscoringsystemid'=>$scoringSystemId, 'color'=>'ffffff',
            'name'=>'TEST_Clear','label'=>'Clear','scoreindex'=>1,'hotkey'=>1)
        );

        $plateType=platetype::create(array(
            'name'=>'PLATETYPE'.$now, 'projectid'=>$sharedProjectId,
            'rows'=>1, 'cols'=>1, 'subs'=>1, 'dropmapping'=>'1,R'
        ))['created'];
        $plateId=plate::create(array(
            'name'=>'PLATE'.$now, 'projectid'=>$defaultProjectId, 'ownerid'=>session::getUserId(),
            'platetypeid'=>$plateType['id'], 'crystalscoringsystemid'=>$scoringSystemId
        ))['created']['id'];

        $imagerId=imager::create(array(
            'name'=>'IMAGER'.$now, 'friendlyname'=>'TestImager'.time(), 'manufacturer'=>'test',
            'temperature'=>20, 'platecapacity'=>100, 'alertlevel'=>80, 'warninglevel'=>95
        ))['created']['id'];

        $imagingParameters=imagingparameters::create(array(
            'name'=>'IP'.$now, 'projectid'=>$sharedProjectId, 'manufacturer'=>'test', 'manufacturerdatabaseid'=>1
        ))['created'];
        $imagingParametersVersionId=imagingparametersversion::create(array(
            'name'=>'IPV'.$now, 'projectid'=>$sharedProjectId,
            'manufacturerdatabaseid'=>1, 'imagingparametersid'=>$imagingParameters['id']
        ))['created']['id'];

        $imagingSessionId=imagingsession::create(array(
            'lighttype'=>'Visible',
            'plateid'=>$plateId,
            'imagerid'=>$imagerId,
            'name'=>'IM_SESS'.$now,
            'imageddatetime'=>'2022-12-31 23:45:59',
            'manufacturerdatabaseid'=>0,
            'imagingparametersversionid'=>$imagingParametersVersionId
        ))['created']['id'];

        session::set('now',$now);
        session::set('defaultProjectId',$defaultProjectId);
        session::set('sharedProjectId',$sharedProjectId);
        session::set('scoringSystemId',$scoringSystemId);
        session::set('plateId',$plateId);
        session::set('imagerId',$imagerId);
        session::set('imagingParametersVersionId',$imagingParametersVersionId);
        session::set('imagingSessionId',$imagingSessionId);
    }

    protected function tearDown(): void {
        database::abort();
        session::destroy();
    }

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testCreate(){
        $wellDrops=plate::getwelldrops(session::get('plateId'));
        $drop=$wellDrops['rows'][0];
        $image=dropimage::create(array(
            'name'=>'IMAGE'.session::get('now'),
            'welldropid'=>$drop['id'],
            'projectid'=>session::get('defaultProjectId'),
            'imagingsessionid'=>session::get('imagingSessionId'),
            'imagestorepath'=>rtrim(session::get('wwwRoot'),'/').'/',
            'imagepath'=>'client/images/dummyimage.jpg',
            'thumbnailpath'=>'client/images/dummythumb.jpg'
        ))['created'];
        static::assertNotNull($image);
    }

    /**
     * @dataProvider getGoodScores
     * @param $score
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testScoreDropImageWithGoodScore($score){
        if(!is_null($score[1])){
            $scores=crystalscoringsystem::getscores(session::get('scoringSystemId'));
            $found=false;
            foreach($scores['rows'] as $s){
                if($s['label']==$score[1]){
                    $score[1]=$s['id'];
                    $found=true;
                    break;
                }
            }
            if(!$found){ self::fail('Score label from getGoodScores not found in test scoring system'); }
        }
        $keys=['humanscorerid', 'latestcrystalscoreid','latestcrystalprobabilitypercent','scoringservicename','scoringenginename'];
        $plateId=session::get('plateId');
        $wellDrops=plate::getwelldrops($plateId);
        $drop=$wellDrops['rows'][0];
        $request=[];
        for($i=0;$i<count($score);$i++){
            if(!is_null($score[$i])){
                $request[$keys[$i]]=$score[$i];
            }
        }
        $imageId=dropimage::create(array(
            'name'=>'IMAGE'.session::get('now'),
            'welldropid'=>$drop['id'],
            'projectid'=>session::get('defaultProjectId'),
            'imagingsessionid'=>session::get('imagingSessionId'),
            'imagestorepath'=>rtrim(session::get('wwwRoot'),'/').'/',
            'imagepath'=>'client/images/dummyimage.jpg',
            'thumbnailpath'=>'client/images/dummythumb.jpg'
        ))['created']['id'];
        dropimage::update($imageId, $request);
        $image=dropimage::getById($imageId);
        self::assertNotNull($image);
    }

    /**
     * @dataProvider getBadScores
     * @param $score
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testScoreDropImageWithBadScore($score){
        if(!is_null($score[1])){
            $scores=crystalscoringsystem::getscores(session::get('scoringSystemId'));
            $found=false;
            foreach($scores['rows'] as $s){
                if($s['label']==$score[1]){
                    $score[1]=$s['id'];
                    $found=true;
                    break;
                }
            }
            if(!$found){ self::fail('Score label from getBadScores not found in test scoring system'); }
        }
        $exceptionMessage=array_pop($score);
        $keys=['humanscorerid', 'latestcrystalscoreid','latestcrystalprobabilitypercent','scoringservicename','scoringenginename'];
        $plateId=session::get('plateId');
        $wellDrops=plate::getwelldrops($plateId);
        $drop=$wellDrops['rows'][0];
        $request=[];
        for($i=0;$i<count($score);$i++){
            if(!is_null($score[$i])){
                $request[$keys[$i]]=$score[$i];
            }
        }
        $imageId=dropimage::create(array(
            'name'=>'IMAGE'.session::get('now'),
            'welldropid'=>$drop['id'],
            'projectid'=>session::get('defaultProjectId'),
            'imagingsessionid'=>session::get('imagingSessionId'),
            'imagestorepath'=>rtrim(session::get('wwwRoot'),'/').'/',
            'imagepath'=>'client/images/dummyimage.jpg',
            'thumbnailpath'=>'client/images/dummythumb.jpg'
        ))['created']['id'];

        $this->expectExceptionMessage($exceptionMessage);
        dropimage::update($imageId, $request);
    }

    /**
     * @return array
     * @throws BadRequestException
     * @throws NotFoundException
     * @throws ServerException
     */
	public static function getGoodScores(): array {
		database::connect();
		session::init(new DummySession());
		session::becomeAdmin();
		$user = user::getFirstAdmin();
		$userId=$user['id'];
		return [
			// humanscorerid, scoreid, probability, scoring service, scoring engine
			'Score "Clear" by human'=>[[$userId, 'Clear', null, null, null]],
			'Probability by human'=>[[$userId, null, 82.3, null, null]],
			'Score "Clear" by auto'=>[[null, 'Clear', null, 'Test Service', 'Test Engine']],
			'Score and probability by auto'=>[[null, 'Crystals', 53.2, 'Test Service', 'Test Engine']],
			'Probability by auto'=>[[null, null, 12, 'Test Service', 'Test Engine']],
		];
	}

    /**
     * @return array[]
     * @throws BadRequestException
     * @throws NotFoundException
     * @throws ServerException
     */
	public static function getBadScores(): array {
		database::connect();
		session::init(new DummySession());
		session::becomeAdmin();
		$user = user::getFirstAdmin();
		$userId=$user['id'];
		return [
			[[null, 'Clear', null, null, null, scoreofdropimage::HUMANSCORER_MISSING_NO_SCORINGSERVICE_OR_SCORINGENGINE]],
			[[null, null, 82.3, null, null, scoreofdropimage::HUMANSCORER_MISSING_NO_SCORINGSERVICE_OR_SCORINGENGINE]],
			[[1+$userId, 'Clear', null, null, null, scoreofdropimage::HUMANSCORERID_USERID_MISMATCH]],
			[[1+$userId, null, 82.3, null, null, scoreofdropimage::HUMANSCORERID_USERID_MISMATCH]],
			[[$userId, 'Clear', null, 'Test Service', 'Test Engine', scoreofdropimage::HUMANSCORER_AND_AUTOSCORER_BOTH_PRESENT]],
			[[$userId, 'Crystals', 53.2, 'Test Service', 'Test Engine', scoreofdropimage::HUMANSCORER_AND_AUTOSCORER_BOTH_PRESENT]],
			[[null, null, 12, 'Test Service', null, scoreofdropimage::HUMANSCORER_MISSING_NO_SCORINGSERVICE_OR_SCORINGENGINE]],
			[[null, null, 12, null, 'Test Engine', scoreofdropimage::HUMANSCORER_MISSING_NO_SCORINGSERVICE_OR_SCORINGENGINE]],
			[[null, null, 123, 'Test Service', 'Test Engine', scoreofdropimage::PROBABILITY_PERCENT_OUT_OF_BOUNDS]],
			[[null, null, -1, 'Test Service', 'Test Engine', scoreofdropimage::PROBABILITY_PERCENT_OUT_OF_BOUNDS]]
		];
	}

}
