<?php

use PHPUnit\Framework\TestCase;

class crystalscoringsystemTest extends TestCase {

    protected function setUp():void {
        database::connect();
        try {
			$now=time();
			database::begin();
            session::init(new DummySession());
            session::becomeAdmin();
            $user=user::create([
				'name'=>'user'.$now,
				'fullname'=>'user'.$now,
				'email'=>'user'.$now.'@bogus.bogus',
			])['created'];
            session::set('user', $user);
            session::set('userId', $user['id']);
            session::revokeAdmin();
        } catch (BadRequestException $e) {
            $this->fail('BadRequestException on session::init, message: '.$e->getMessage());
        } catch (NotFoundException $e) {
            $this->fail('NotFoundException on session::init, message: '.$e->getMessage());
        } catch (ServerException $e) {
            $this->fail('ServerException on session::init, message: '.$e->getMessage());
        } catch (ForbiddenException $e) {
			$this->fail('ForbiddenException on session::init, message: '.$e->getMessage());
		}
	}

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

	/**
	 * @throws BadRequestException
	 * @throws ServerException
	 */
    public function testCanCreateAsAdmin(){
        session::becomeAdmin();
        $this->assertTrue(crystalscoringsystem::canCreate());
    }

    /**
     * @throws BadRequestException
     * @throws NotFoundException
     * @throws ServerException
     * @throws ForbiddenException
     */
    public function testCanCreateAsTechnician(){
        session::becomeAdmin();
        $group=usergroup::getByName(usergroup::TECHNICIANS);
        groupmembership::create(array('userid'=>session::getUserId(), 'usergroupid'=>$group['id']));
        session::revokeAdmin();
        session::refreshProjectPermissions();
        $this->assertTrue(crystalscoringsystem::canCreate());
    }

	/**
	 * @throws BadRequestException
	 * @throws ServerException
	 */
    public function testCanCreateAsNonAdmin(){
		$this->assertFalse(session::isAdmin());
        $this->assertFalse(crystalscoringsystem::canCreate());
    }

	/**
	 * @throws ServerException
	 * @throws BadRequestException
	 */
	public function testCreateAsAdmin(){
        session::becomeAdmin();
		self::assertTrue(session::isAdmin());
        try {
            $created=crystalscoringsystem::create(array('name'=>'test'.time()));
            $this->assertNotEmpty($created);
            $this->assertNotEmpty(crystalscoringsystem::getById($created['created']['id']));
        } catch (ForbiddenException){
            $this->fail('Could not create crystalscoringsystem as admin (ForbiddenException)');
        } catch (Exception){
            $this->fail('Could not create crystalscoringsystem as admin (not a ForbiddenException)');
        }

    }

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testCreateAsNonAdmin(){
		self::assertFalse(session::isAdmin());
		self::assertFalse(session::isTechnician());
		self::expectException('ForbiddenException');
        crystalscoringsystem::create(array('name'=>'test'.time()));
    }

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testGetById(){
		session::becomeAdmin();
        $created=crystalscoringsystem::create(array('name'=>'test'.time()));
        $id=$created['created']['id'];
        //Get by ID as admin
        $crystalscoringsystem=crystalscoringsystem::getById($id);
        $this->assertArrayHasKey('name', $crystalscoringsystem);
        //getById as non-admin
        session::revokeAdmin();
        $crystalscoringsystem=crystalscoringsystem::getById($id);
        $this->assertArrayHasKey('name', $crystalscoringsystem);
    }

    /**
     * @throws BadRequestException
     * @throws ForbiddenException
     * @throws NotFoundException
     * @throws ServerException
     */
    public function testGetByName(){
        session::becomeAdmin();
        $name='test'.time();
        crystalscoringsystem::create(array('name'=>$name));
        //Get by ID as admin
        $crystalscoringsystem=crystalscoringsystem::getByName($name);
        $this->assertArrayHasKey('name', $crystalscoringsystem);
        //getById as non-admin
        session::revokeAdmin();
        $crystalscoringsystem=crystalscoringsystem::getByName($name);
        $this->assertArrayHasKey('name', $crystalscoringsystem);
    }

	/**
	 * @throws NotFoundException
	 * @throws ForbiddenException
	 * @throws BadRequestException
	 * @throws ServerException
	 */
	public function testGetScoreBestMatchingName(){
        session::becomeAdmin();
        $scoringSystem=crystalscoringsystem::create(array(
            'name'=>'SS'.time(),

        ))['created'];
        self::assertNotNull($scoringSystem, 'Could not find scoring system after creation');
        $scores=array(
            array('scoreindex'=>1, 'hotkey'=>3, 'color'=>'ffffff', 'label'=>'ABCDE'),
            array('scoreindex'=>2, 'hotkey'=>2, 'color'=>'ffffff', 'label'=>'BCDEF'),
            array('scoreindex'=>3, 'hotkey'=>1, 'color'=>'ffffff', 'label'=>'CDEFG')
        );
        foreach ($scores as $score){
            $score['crystalscoringsystemid']=$scoringSystem['id'];
            $score['name']=$scoringSystem['name'].'_'.$score['label'];
            crystalscore::create($score);
        }
		session::revokeAdmin();
        $score=crystalscoringsystem::getScoreBestMatchingName($scoringSystem['id'],'ABCDE');
        self::assertNotNull($score, 'getScoreBestMatchingName: Exact match failed');
        self::assertEquals('ABCDE', $score['label'], 'getScoreBestMatchingName: Exact match returned wrong result');
        $score=crystalscoringsystem::getScoreBestMatchingName($scoringSystem['id'],'BCDE');
        self::assertNotNull($score, 'getScoreBestMatchingName: Begins-with match failed');
        self::assertEquals('BCDEF', $score['label'], 'getScoreBestMatchingName: Begins-with match returned wrong result');
        $score=crystalscoringsystem::getScoreBestMatchingName($scoringSystem['id'],'CDE');
        self::assertNotNull($score, 'getScoreBestMatchingName: Name-contains match failed');
        self::assertNotEquals('CDEF', $score['label'], 'getScoreBestMatchingName: Name-contains match did not return highest-score match');
        self::assertEquals('CDEFG', $score['label'], 'getScoreBestMatchingName: Name-contains match returned wrong result');
        $score=crystalscoringsystem::getScoreBestMatchingName($scoringSystem['id'],'abcde');
        self::assertNotNull($score, 'getScoreBestMatchingName: Lowercase match failed');
        self::assertEquals('ABCDE', $score['label'], 'getScoreBestMatchingName: Lowercase match returned wrong result');
        $score=crystalscoringsystem::getScoreBestMatchingName($scoringSystem['id'],'DEFGH');
        self::assertNull($score, 'Search for non-existent string returned a match');
    }

}
