<?php

namespace App\Services\Upkeep;

use ReallySimpleJWT\Token;
use ReallySimpleJWT\Exception\BuildException;
use App\Services\Assets\DocService;
use Carbon\Carbon;

use function _\find;

class InitService
{
    protected $docs;

    public function __construct(DocService $docService)
    {
        $this->docs = $docService;
    }

    private static function validSecret($length)
    {
        $alphanum        = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        $special         = '*&!@%^#$';
        $alphabet        = $alphanum . $special;
        $random          = openssl_random_pseudo_bytes($length);
        $alphabet_length = strlen($alphabet);
        $string          = '';
        for ($i = 0; $i < $length; ++$i) {
            $string .= $alphabet[ord($random[$i]) % $alphabet_length];
        }
        //secret needs to be a valid token
        if ($length == 12) {
            try {
                $secret = Token::create(12, $string, time() + 3600, 'localhost');
                return $string;
            } catch (BuildException $e) {
                //bad secret, so try agiain
                return self::validSecret(12);
            }

            if (Token::validate($key, $string)) {
                return $string;
            } else {
                return self::validSecret(12);
            }
        }
    }

    public function fresh($body)
    {
        //grab template files
        //TODO: Remove hardcoded link and set up init path in settings
        $newFolks = json_decode(
            file_get_contents('../content/init/folks-template.json'),
            true
        );
        $newSettings = json_decode(
            file_get_contents('../content/init/settings-template.json'),
            true
        );
        //get form values
        //$body = $request->getParsedBody();
        $handle = $body->new_member_handle;
        $email  = $body->new_member_email;
        $pass   = $body->new_member_pass;
        $title  = $body->new_member_title;

        $now = Carbon::now();
        //setup folks config
        $hash                    = password_hash($pass, PASSWORD_DEFAULT);
        $newFolks[0]['id']       = 0;
        $newFolks[0]['handle']   = $handle;
        $newFolks[0]['email']    = $email;
        $newFolks[0]['password'] = $hash;
        $newFolks[0]['key']      = password_hash($email, PASSWORD_DEFAULT);
        $newFolks[0]['secret']   = self::validSecret(12);
        $newFolks[0]['role']     = 'hnic';
        $newFolks[0]['created']  = $now->format("Y-m-d\TH:i:sP");
        $newFolks[0]['updated']  = $now->format("Y-m-d\TH:i:sP");
        //set up settings config
        $newSettings['global']['title'] = $title;

        //create index file
        $index = [
            'id'        => 1,
            'uuid'      => createUUID(),
            'title'     => 'FIRST!',
            'imageList' => '/assets/images/global/default-bg.jpg',
            'fileList'  => '',
            'path'      => 'content/pages/start',
            'layout'    => 'index',
            'tags'      => 'start, welcome',
            'author'    => $handle,
            'created'   => $now->format("Y-m-d\TH:i:sP"),
            'updated'   => $now->format("Y-m-d\TH:i:sP"),
            'deleted'   => 'false',
            'slug'      => 'first',
            'menu'      => 'false',
            'featured'  => 'false',
            'published' => 'true',
            'content'   => "# F**k Yes \n\nIf you're seeing this, you're up and running. NICE WORK!\n\nFrom here, feel free to start dropping pages to your heart's content.\n\nFor some tips about using Fipamo, check out the ![docs](https://code.playvicio.us/Are0h/Fipamo/wiki/02-Usage)\n\nAll good? Feel free to edit this page to whatever you want!\n\nYOU'RE THE CAPTAIN NOW.",
        ];

        //once all files created, write down
        $this->docs->writeSettings($newSettings, '../content/config/settings.json');
        $this->docs->writeSettings($newFolks, '../content/config/folks.json');
        $this->docs->writeSettings([], '../content/config/tags.json');
        $object = (object) $index;

        $this->docs->writePages(
            'create',
            'start',
            '../content/pages/start/index.md',
            $this->docs::objectToMD($object)
        );

        $result = ['type' => 'blogInitGood', 'message' => 'Site Created'];

        return $result;
    }

    public function restore($request)
    {
        $file = $request->file('backup-upload');
        $file->move('../content' . '/', $file->getClientOriginalName());
        $zip     = new \ZipArchive();
        $result  = [];
        $tempDir = '../content/_temp';
        if ($zip->open('../content' . '/' . $file->getClientOriginalName()) === true) {
            $folks = json_decode($zip->getFromName('config/folks.json'), true);
            $found = find($folks, ['handle' => $request->restore_member_handle]);
            if ($found) {
                if (password_verify($request->restore_member_pass, $found['password'])) {
                    //restore assets from previous site
                    $this->moveAssets($zip, $request->restore_former_url);
                    $newFolks = [];
                    if (!isset($found['secret'])) {
                        $found['secret'] = self::validSecret(12);
                    }
                    array_push($newFolks, $found);
                    //make temp folder and dump file in there
                    mkdir($tempDir, 0755, true);
                    $zip->extractTo($tempDir);
                    //load up old config file
                    $newConfig = json_decode(
                        file_get_contents($tempDir . '/config/settings.json'),
                        true
                    );
                    //check for key, add if not there
                    if (!isset($newConfig['global']['externalAPI'])) {
                        $newConfig['global']['externalAPI'] = 'false';
                    }
                    //make dir and write new config files
                    if (!is_dir('../content/config/')) {
                        mkdir('../content/config/', 0755, true);
                    }
                    $this->docs->writeSettings($newConfig, '../content/config/settings.json');
                    $this->docs->writeSettings($newFolks, '../content/config/folks.json');
                    rename($tempDir . '/config/tags.json', '../content/config/tags.json');
                    //move saved markdown pages
                    rename($tempDir . '/content/pages/', '../content/pages');
                    //clean up temp dir and zip file
                    $this->docs::deleteFolder($tempDir);
                    $zip->close();
                    unlink('../content/' . $file->getClientOriginalName());
                    $result = [
                        'type'    => 'requestGood',
                        'message' => 'Site Restored! Redirecting',
                    ];
                } else {
                    $result = [
                        'type'    => 'requestLame',
                        'message' => 'Check that password, champ.',
                    ];
                }
            } else {
                $result = [
                    'type'    => 'requestLame',
                    'message' => 'Could not open backup. RATS!',
                ];
            }
        };
        return $result;
    }

    private function moveAssets($zip, $url)
    {
        $assetFail = 0;
        $assetList = [];
        array_push($assetList, json_decode($zip->getFromName('assets/blog_images.json'), true));
        array_push($assetList, json_decode($zip->getFromName('assets/user_images.json'), true));
        array_push($assetList, json_decode($zip->getFromName('assets/blog_docs.json'), true));
        array_push($assetList, json_decode($zip->getFromName('assets/blog_videos.json'), true));
        foreach ($assetList as $list) {
            foreach ($list as $asset) {
                $path    = explode('/', $asset['path']);
                $type    = $path[3];
                $section = $path[4];
                $year    = $path[5];
                $month   = $path[6];
                $blogDir = '../public/assets/' . $type . '/' . $section . '/' . $year . '/' . $month;
                if (!is_dir($blogDir)) {
                    mkdir($blogDir, 0755, true);
                }
                $externalPath = '/assets/' . $type . '/' . $section . '/' . $year . '/' . $month;
                $asset_url    = $url . $externalPath . '/' . $asset['file'];
                try {
                    file_put_contents(
                        $asset['path'] . '/' . $asset['file'],
                        file_get_contents($asset_url)
                    );
                } catch (\Throwable $e) {
                    $assetFail++;
                }
            }
        }
    }
}