<?php

include_once 'DeviceTest.php';

class FormulatrixImportTest extends DeviceTest {

    /**
     * @throws ServerException
     * @throws BadRequestException
     */
    public function testGetLatestImagingTask(){
        $result=FormulatrixImport::getLatestImagingTask();
        echo 'getLatestImagingTask: '.json_encode($result);
        self::assertNotEmpty($result);
        self::assertArrayHasKey("fxImagingTaskId", $result);
        self::assertArrayHasKey("dateTime", $result);
        self::assertArrayHasKey("numImages", $result);
        self::assertFalse(0==$result["dateTime"]);
        self::assertFalse(0==$result["fxImagingTaskId"]);
    }

    /**
     * @throws ServerException
     * @throws BadRequestException
     */
    public function testGetImagingTaskById(){
        $latest=FormulatrixImport::getLatestImagingTask();
        $result=FormulatrixImport::getImagingTaskByFormulatrixId(
            array('id'=>$latest['fxImagingTaskId'])
        );
        echo 'getImagingTaskById: '.json_encode($result);
        self::assertNotEmpty($result);
        self::assertArrayHasKey("fxImagingTaskId", $result);
        self::assertArrayHasKey("dateTime", $result);
        self::assertArrayHasKey("numImages", $result);
        self::assertFalse(0==$result["fxImagingTaskId"]);
        self::assertFalse(0==$result["dateTime"]);
    }

    /**
     * @throws ServerException
     * @throws BadRequestException
     * @throws NotFoundException
     */
    public function testGetScores(){
        $scores=FormulatrixImport::getScores();
        echo 'getScores: '.json_encode($scores);
        self::assertNotEmpty($scores);
        self::assertArrayHasKey("id", $scores[0]);
        self::assertArrayHasKey("label", $scores[0]);
        self::assertArrayHasKey("color", $scores[0]);
        self::assertArrayHasKey("hotkey", $scores[0]);
        self::assertArrayHasKey("scoreindex", $scores[0]);
    }

    /**
     * @throws BadRequestException
     * @throws NotFoundException
     * @throws ForbiddenException
     * @throws ServerException
     */
    public function testCreateScores(){
        $scoringSystemName="scoreSystem".time();
        $scores=FormulatrixImport::getScoresWithScoringSystemName($scoringSystemName);
        self::assertEmpty($scores);
        $scores=FormulatrixImport::getScores();
        self::assertNotEmpty($scores);
        foreach ($scores as &$score){
            //Scores come from Fx as decimal numbers, but IceBear stores them as hex. Force a decimal.
            $score['color']=255;
            //Icebear "name" is for uniqueness only and not used/returned. Set label as name.
            $score['name']=$score['label'];
        }
        $params=array('scores'=>$scores);
        $created=FormulatrixImport::createScoresWithScoringSystemName($params, $scoringSystemName);
        self::assertNotEmpty($created);
        self::assertNotEmpty($created['scores']);
        self::assertEquals('ffff01',$created['scores'][0]['color']);
        echo 'createScores: '.json_encode($created);
    }

    /**
     * User
     */

    const USER_JSON='{
        "fullName":"Automated Test [[TIME]]",
        "email":"test.[[TIME]]@bogus.net"
    }';

    /**
     * @return mixed
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    private function createUser(){
        $params=json_decode(str_replace('[[TIME]]', time(), self::USER_JSON), true);
        return FormulatrixImport::createUser($params);
    }

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testCreateUser(){
        $result=self::createUser();
        self::assertNotEmpty($result);
        echo 'createUser: '.json_encode($result);
    }

    /**
     * Plate type
     */

    const PLATETYPE_JSON='{
        "name":"PLATETYPE_[[TIME]]",
        "rows":8,
        "columns":12,
        "subpositions":3
    }';

    /**
     * @return array|mixed
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    private function createPlateType(){
        $params=json_decode(str_replace('TIME', time(), self::PLATETYPE_JSON), true);
        return FormulatrixImport::createPlateType($params);
    }

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testCreatePlateType(){
        $result=self::createPlateType();
        self::assertNotEmpty($result);
        self::assertEquals('123,RRR',$result['dropmapping']);
        echo 'createPlateType: '.json_encode($result);
    }

    /**
     * Plate
     */

    const PLATE_JSON='{
            "barcode":"PLATE_[[TIME]]",
            "scoringSystemName":"[[SCORING_SYSTEM_NAME]]",
            "plateType":[[PLATETYPE_JSON]],
            "owner":[[USER_JSON]],
            "scores":[[SCORES]]
    }';

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws ServerException
     * @throws NotModifiedException
     * @throws NotFoundException
     */
    private function createPlate(){
        $scoringSystemName='Fx_'.time();
        $scores=FormulatrixImport::getScores();
        foreach ($scores as &$score){
            $score['color']=255;
            $score['name']=$score['label'];
        }
        $params=array('scores'=>$scores);
        FormulatrixImport::createScoresWithScoringSystemName($params, $scoringSystemName);
        $json=str_replace('[[PLATETYPE_JSON]]', self::PLATETYPE_JSON, self::PLATE_JSON);
        $json=str_replace('[[SCORING_SYSTEM_NAME]]', $scoringSystemName, $json);
        $json=str_replace('[[USER_JSON]]', self::USER_JSON, $json);
        $json=str_replace('[[TIME]]', time(), $json);
        $json=str_replace('[[SCORES]]', json_encode($scores), $json);
        $params=json_decode($json, true);
        return FormulatrixImport::createPlate($params);
    }

    /**
     * @throws NotModifiedException
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testCreatePlate(){
        $result=self::createPlate();
        self::assertNotEmpty($result);
        $drops=plate::getwelldrops($result['id']);
        self::assertNotEmpty($drops);
        self::assertEquals('288', $drops['total']);
        session::becomeAdmin();
        $welldrop=welldrop::getByPlateIdAndRowColumnDrop($result['id'], 1, 1, 1);
        self::assertNotEmpty($welldrop);
    }

    /**
     * Imager
     */
    const IMAGER_JSON='{
        "name":"RI99-[[TIME]]",
        "temperature":20
    }';

    /**
     * @throws ForbiddenException
     * @throws BadRequestException
     * @throws NotFoundException
     * @throws ServerException
     */
    private function createImager(): array {
        $json=str_replace('[[TIME]]', time(), self::IMAGER_JSON);
        $params=json_decode($json, true);
        return FormulatrixImport::createImager($params);
    }

    /**
     * @throws ForbiddenException
     * @throws BadRequestException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testCreateImager(){
        $result=self::createImager();
        self::assertNotEmpty($result);
    }

    /**
     * Imaging parameters and settings
     */

    const IMAGING_SETTINGS_JSON='{
            "captureProfile":{
                "name":"Test settings [[TIME]]",
                "id":"[[TIME]]",
                "currentVersionId":[[TIME]]0,
                "settings":{
                    "LightPath":"Visible",
                    "TestSetting":"Test"
                }
            },
            "imager":[[IMAGER_JSON]]
        }';

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    private function createImagingSettings(){
        $json = str_replace("[[IMAGER_JSON]]", self::IMAGER_JSON, self::IMAGING_SETTINGS_JSON);
        $json = str_replace("[[TIME]]", time(), $json);
        $params = json_decode($json, true);
        $imagerName = $params['imager']['name'];
        $result=FormulatrixImport::createImagingSettings($params);
        //Add these three items needed by the test
        $result['imagerName']=$imagerName;
        $result['captureProfileName']=$params['captureProfile']['name'];
        $result['captureProfileId']=$params['captureProfile']['id'];
        $result['captureProfileVersionId']=$params['captureProfile']['currentVersionId'];
        return $result;
    }

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws ServerException
     * @throws NotFoundException
     */
    public function testCreateImagingSettings(){
        $result=self::createImagingSettings();
        self::assertNotEmpty($result);
        echo 'testCreateImagingSettings: '.json_encode($result);
        self::assertNotEmpty(imager::getByName($result['imagerName']));
        self::assertNotEmpty(imagingparameters::getByName($result['captureProfileName']));
        $imagingParameters=imagingparameters::getByProperty('manufacturerdatabaseid',$result['captureProfileId']);
        echo "\n".'imagingParameters in testCreateImagingSettings: '.json_encode($imagingParameters);
        self::assertNotEmpty($imagingParameters);
        $imagingParameters=$imagingParameters['rows'][0];
        $imagingParametersVersion=imagingparametersversion::getById($imagingParameters['currentversionid']);
        echo "\n".'imagingParametersVersion in testCreateImagingSettings: '.json_encode($imagingParametersVersion);
        self::assertNotEmpty($imagingParametersVersion);
        self::assertNotEmpty($imagingParameters['currentversionid']);
        self::assertEquals($imagingParametersVersion['imagingparametersid'], $imagingParameters['id']);
        self::assertEquals($imagingParameters['currentversionid'], $imagingParametersVersion['id']);
    }

    /**
     * Imaging session
     */

    /**
     * @throws BadRequestException
     * @throws NotFoundException
     * @throws ServerException
     * @throws ForbiddenException
     * @throws NotModifiedException
     */
    private function createImagingSession(){
        $imagingParameters = self::createImagingSettings();
        $imagerName = $imagingParameters['imagerName'];
        echo 'Settings in testCreateImagingSession: ' . json_encode($imagingParameters);
        $captureProfileVersionId = $imagingParameters['captureProfileVersionId'];
        $imagingParametersVersion = imagingparametersversion::getById($imagingParameters['currentversionid']);
        echo "\n" . 'captureProfileVersion in testCreateImagingSession: ' . json_encode($imagingParametersVersion);
        $plate = self::createPlate();
        $plateBarcode = $plate['name'];

        session::revertAdmin();
        $date = new DateTime();
        return FormulatrixImport::createImagingSession(json_decode('{
            "plateBarcode":"' . $plateBarcode . '",
            "imagingTaskId":"' . time() . '",
            "captureProfileVersionId":' . $captureProfileVersionId . ',
            "imagerName":"' . $imagerName . '",
            "temperature":20,
            "imagedDateTime":"' . date_format($date, 'Y-m-d H:i:s') . '"
        }', true));
    }

    /**
     * @throws NotFoundException
     * @throws NotModifiedException
     * @throws ForbiddenException
     * @throws BadRequestException
     * @throws ServerException
     */
    public function testCreateImagingSession(){
        $result=self::createImagingSession();
        self::assertNotEmpty($result);
        echo 'testCreateImagingSession: '.json_encode($result);
    }

    /**
     * Image and thumbnail
     */


    /**
     * @return void
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws NotModifiedException
     * @throws ServerException
     */
    public function testCreateImage(){
        $imagePath=__DIR__.'/../../testVisibleImage.jpg';
        $thumbPath=__DIR__.'/../../testVisibleThumb.jpg';
        $imagingSession=self::createImagingSession();
        $json='{
            "iceBearImagingSessionId":'.$imagingSession['id'].',
            "iceBearPlateId":'.$imagingSession['plateid'].',
            "wellRowNumber":2,
            "wellColumnNumber":3,
            "wellDropNumber":2,
            "micronsPerPixel":1.5,
            "image":"'.base64_encode(file_get_contents($imagePath)).'",
            "thumb":"'.base64_encode(file_get_contents($thumbPath)).'"
        }';
        $params=json_decode($json, true);
        $image=FormulatrixImport::createImage($params);
        self::assertNotEmpty($image);
    }

    /**
     * @throws NotFoundException
     * @throws ForbiddenException
     * @throws BadRequestException
     * @throws ServerException
     * @throws Exception
     */
    public function testGetScoresOverHttp(){
        $config = json_decode(@file_get_contents(__DIR__ . '/../../../../testconfig.json'), true);
        $apiRoot=$config['iceBearWwwRoot'];
        session::becomeAdmin();
        $apiKey=apikey::create(array('scope'=>'FormulatrixImport'));
        $apiKeyId=$apiKey['created']['id'];
        $apiKey=$apiKey['created']['key'];
        database::commit();

        $payload=array();
        $result=DeviceTest::post($apiRoot.'/device/FormulatrixImport/getScores',json_encode($payload), $apiKey);
        echo $result;
        $result=json_decode($result,true);

        database::begin();
        apikey::delete($apiKeyId);
        database::commit();
        session::revokeAdmin();

        database::begin();

        self::assertIsArray($result);
        self::assertArrayNotHasKey("error",$result);

    }

    /**
     * @throws NotFoundException
     * @throws ForbiddenException
     * @throws BadRequestException
     * @throws ServerException
     * @throws Exception
     */
    public function testGetScoresOverHttpWithPayload(){
        $config = json_decode(@file_get_contents(__DIR__ . '/../../../../testconfig.json'), true);
        $apiRoot=$config['iceBearWwwRoot'];
        session::becomeAdmin();
        $apiKey=apikey::create(array('scope'=>'FormulatrixImport'));
        $apiKeyId=$apiKey['created']['id'];
        $apiKey=$apiKey['created']['key'];
        database::commit();

        $payload=json_decode('{"scores":[
            {"color":-10185235,"name":"Clear","hotkey":"0"},{"color":-16776961,"name":"Dust","hotkey":"1"},
            {"color":-16776961,"name":"Granular Precipitate","hotkey":"2"},
            {"color":-16744320,"name":"Full Precipitate","hotkey":"3"},
            {"color":-16744448,"name":"Good Precipitate","hotkey":"4"},
            {"color":-16711936,"name":"Phase Separation","hotkey":"5"},
            {"color":-6751336,"name":"Microcrystalline","hotkey":"6"},
            {"color":-256,"name":"Needles (1D)","hotkey":"7"},
            {"color":-23296,"name":"Plates (2D)","hotkey":"8"},
            {"color":-65536,"name":"Crystals (3D)","hotkey":"9"}
        ]}', true);
        $result=DeviceTest::post($apiRoot.'/device/FormulatrixImport/getScores',json_encode($payload), $apiKey);
        echo $result;
        $result=json_decode($result,true);

        database::begin();
        apikey::delete($apiKeyId);
        database::commit();
        session::revokeAdmin();

        database::begin();

        self::assertIsArray($result);
        self::assertArrayNotHasKey("error",$result);

    }



}