<?php

namespace MyDevel\Webroot\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\HttpKernel\KernelInterface;



use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;


use MyDevel\Webroot\Entity\WebrootUser;

abstract class WebrootSetupController extends AbstractController
{
    /**
     * 
     * @var string|null Project root directory.
     */
    private ?KernelInterface $kernel = null;
    private ?string $project_dir = null;
    
    
    public function __construct(KernelInterface $kernel) {
        $this->kernel = $kernel;
        $this->project_dir = $kernel->getProjectDir();
    }
    
    /**
     * @brief Get the root directory of the Project.
     * 
     * This method gets the root directory of the project as an absolute path
     * as returned by the Kernel->getProjectDir();
     * 
     * @return string|null The root directory of the prject or null if the 
     * Kernel cannot determine it.
     */
    public function getProjectDir(): ?string
    {
        return $this->project_dir;
    }
    
    /**
     * @brief Check if there is an Administrator account existing. 
     * @return bool `true` if an Administrator is existent in the database.
     */
    protected function hasAdministrator(): bool
    {
        $repos = $this->getRpository(WebrootUser::class);
        return $repos->hasAdministrator();        
    }
    
    /**
     * @brief Check if there is a *.setupkey*-file in the project root.
     * 
     * @note This file will be deleted after the initial setup!
     * 
     * @return bool `true` if there is a *.setupkey* file int the project
     *      root directory.
     */
    protected function hasSetupKey(): bool
    {
        return file_exists(join(DIRECTORY_SEPARATOR,[$this->project_dir,".setupkey"]));
    }
    
    /**
     * @Brief Get the actual setup key from file.
     * @return string|null Returns `null` when there is no `.setupkey` file
     *      located in prject root else the first line of the file.
     */
    protected function getSetupKey(): ?string
    {
        if (!$this->hasSetupKey()) {
            return null;
        }
        $file = fopen($this->project_dir,".setupkey");
        $str = fread($file, 4096);
        fclose($file);
        $pos = strpos($str,"\r\n",0);
        if (!$pos) {
            $pos = strpos($str,"\n",0);
        }
        if ($pos) {
            $key=substr(string,0,pos);
        } else {
            $key=$str;
        }
        return key;        
    }
    
    /**
     * @brief Check if user is logged in for setup.
     * @return bool Returns `true` if user is logged in and is allowed to view
     *      the setup pages.
     */
    public function isLoggedIn(): bool
    {
        $user = $this->getUser();
        if ($user && $user->isAdmin()) {
            return true;
        }
        
        $has_setup_key = $this->hasSetupKey();
        $has_administrator = $this->hasAdministrator();
        if (!$has_administrator && !$has_setup_key) {
            return true;
        }
        
        if ($has_setup_key && isset($_COOKIE["mydevel_webroot_sk"])) {
            return (filter_input(INPUT_COOKIE, "mydevel_webroot_sk") === $this->getSetupKey());
        }
        
        return false;
    }
    
    /**
     * @brief Check if we are already set up.
     * 
     * This method checks if there is an .env.local file installed in the 
     * system and returns ture if the .env.local file is found.
     * 
     * @return bool `true` if we are already installed.
     */
    public function isInstalled(): bool
    {
        return (file_exists(join(DIRECTORY_SEPARATOR,[$this->project_dir,".env"]))
                && file_exists(join(DIRECTORY_SEPARATOR,[$this->project_dir,".env.local"])));
    }
    
    /**
     * @brief Check if the key marches the one from file.
     * 
     * @param string $key The key to check.
     * 
     * @return bool|null Returns `null` if there is no *.setupkey* file present,
     *      `true` on match and false if the key does not match.
     */
    protected function checkSetupKey(string $key): ?bool
    {
        if (!$this->hasSetupKey()) {
            return null;
        }
        
        $file_key = $this->getSetupKey();
        if ($key === $file_key) {
            $cookie_domain = getenv("WEBROOT_HOST");
            if (!$cookie_domain || !strlen("WEBROOT_HOST")) {
                $request = $this->getRequest();
                $cookie_domain = $request->getHost();
                setcookie("mydevel_webroot_sk",$file_key,0,"/",$cookie_domain,1,0);
                return true;
            }
        }
        return false;
    }
    
    /**
     * 
     * @return string
     */
    protected function runMakeMigration(): string
    {
        $application = new Application($this->kernel);
        $application->setAutoExit(false);
        
        $input = new ArrayInput([
            "command" => "make:migration",
            "--formatted" => true,
            "--no-interaction" => true,
        ]);
        
        $output = new BufferedOutput();
        $application->run($input,$output);
        
        $content=$output->fetch();
        
        return $content;
    }
    
    /**
     * 
     * @return string
     */
    protected function runMigrate(): string
    {
        $application = new Application($this->kernel);
        $application->setAutoExit(false);
        
        $input = new ArrayInput([
                "command" => "doctrine:migrations:migrate",
                "--no-interaction" => true,
        ]);
        $output = new BufferedOutput();
        $application->run($input,$output);
        
        $content = $output->fetch();
        
        return $content;
    }
}
