<?php

namespace Tests\Unit;

use PHPUnit\Exception;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\PHPTAssertionFailedError;
use PHPUnit\Framework\TestCase;
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
use FilesystemIterator;

class QualityControlTest extends TestCase
{
    private $non_standard_folders = [];

    private $file_check=[];

    private $results = [];

    public const CODE_LINE_COUNT = 400;

    public const METHOD_COUNT = 20;

    public function __construct(?string $name = null, array $data = [], string $dataName = '')
    {
        //Unit test defaults
        parent::__construct($name, $data, $dataName);

        $fullPath = dirname(__FILE__, 3).'/app/Classes/Modules';
        $dirs = $files = [];

        $modules_dir_count = [];

        $current_directory = "";
        $allowed_folders = ['ControllersLogic','DataTransferObjects','Processors','Services','Standards'];
        $allowed_standards_folders = ['Criteria','Criterias','Rules','Validators'];
        $ignore_folders = ['Rates'];

        $directory = new RecursiveDirectoryIterator($fullPath, FilesystemIterator::SKIP_DOTS);

        $modules = array_map('basename',glob($fullPath.'/*', GLOB_ONLYDIR));

        foreach (new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST) as $path ) {

            //Note: $path is SplFileInfo class. For all the options/methods , please check here: https://www.php.net/manual/en/class.splfileinfo.php

            if($path->isDir()){
                //Check Modules directory for allowed folders
                //TODO: Check folder in correct orders, e.g. if Validators inside Standards folder

                $dirs[] = $path->__toString();

                if(in_array($path->getFileName(),$modules)){
                    $current_directory = $path->getFileName();
                    $modules_dir_count[$path->getFileName()]=['count'=>0,'standards_count'=>0];
                }else if(in_array($path->getFileName(),$allowed_folders)){
                    $modules_dir_count[$current_directory]['count'] += 1;
                }else if(in_array($path->getFileName(),$allowed_standards_folders)){
                    $modules_dir_count[$current_directory]['standards_count'] += 1;
                } else if(!in_array($path->getFileName(),$ignore_folders)){
                    $this->non_standard_folders[]= $path->__toString();
                }
            }else{
                $files[] = realpath($path->__toString());

                //TODO: Read files (.php) & check for class name format & if possible variable name format

                $file = $path->openFile('r');
                if(!isset($this->file_check[$path->getFileName()]['files'])){
                    $this->file_check[$path->getFileName()]=['lines'=>0,'methods_count'=>0];
                }
                $file->seek(PHP_INT_MAX);
                $linesTotal = $file->key();
                $this->file_check[$path->getFileName()]['lines'] = $linesTotal;


                //Note: Use reflection to get class info :  https://www.php.net/manual/en/class.reflectionclass.php
                $namespace = str_replace($fullPath."/","",$file->getPath());
                $namespace = str_replace("/","\\",$namespace);
                $class_name = "App\Classes\Modules\\".$namespace."\\".$file->getBasename('.php');

                $class = new \ReflectionClass($class_name);
                $class_methods = $class->getMethods();

                $this->file_check[$path->getFileName()]['methods_count'] = count($class_methods);

            }

        }

        //var_dump($files, $dirs);
        //var_dump($this->file_check);
        //var_dump($modules_dir_count,$non_standard_folders);
        //die('debug');
    }

    public function checkCodeStandards()
    {
        foreach ($this->file_check as $filename => $file) {
            $this->results['code line'] = $this->assertLessThanOrEqual($this::CODE_LINE_COUNT, $file['lines'],'Please check '.$filename.', the code line is '.$file['lines']);
            $this->results['code method'] = $this->assertLessThanOrEqual($this::METHOD_COUNT,$file['methods_count']);
        }
    }

    public function checkFolderStandards()
    {
        $this->results['folder check'] = $this->assertCount(0,$this->non_standard_folders ,"Found non standard folders");
    }

    public function testQualityCheck(){
        $this->checkCodeStandards();
        $this->checkFolderStandards();

        print_r($this->results);
    }

}
