<?php

namespace Arcadia\Dev;

/**
 * Block code generator
 */
class Builder
{
    /**
     * Tracked Groups
     * @var array
     */
    private static $group_names = [
        'Content',
        '(Block) Content with Sidebar',
    ];

    /**
     * Process request
     * @return void
     */
    public static function init()
    {
        add_action('save_post', [__CLASS__, 'bootstrapBlock'], 50, 2);
    }

    /**
     * Create blocks as required
     * @param  integer $post_id Post ID
     * @param  object  $post    Post details
     * @return integer          Post ID
     */
    public static function bootstrapBlock($post_id, $post)
    {
        if (($post->post_type !== 'acf-field-group' && !in_array($post->post_title, self::$group_names))
            || wp_is_post_revision($post_id)
            || $post->post_status == 'auto-draft') {
            return $post_id;
        }

        switch ($post->post_title) {
            case 'Content':
                self::coreBlock();
                break;
            case '(Block) Content with Sidebar':
                self::nestedBlock();
                break;
        }

        return $post_id;
    }

    /**
     * Generate core blocks
     */
    private static function coreBlock()
    {
        $group = acf_get_fields('group_572229fc5045c');
        self::generateTopLevelBlock($group);
    }

    /**
     * Generate content with sidebar blocks
     */
    private static function nestedBlock()
    {
        $group = acf_get_fields('group_59eeada158b78');

        self::generateSecondLevelBlock($group, 'content_rows', 'blocks/content', 'content-blocks');
        self::generateSecondLevelBlock($group, 'side_rows', 'blocks/sidebar', 'sidebar-blocks');
    }

    /**
     * Create higher level blocks
     * @param  array $group ACF Group
     * @return void
     */
    private static function generateTopLevelBlock($group)
    {
        $blocks = self::findMissingBlocks($group, 'blocks');

        array_walk($blocks, function ($block, $key) {
            self::cloneBlock($block);
            self::clonePartial($block);
            self::appendPartial($block);
        });
    }

    /**
     * Create second tier blocks
     * @param  array  $root_block ACF Block
     * @param  string $row_name   Block to seek
     * @param  string $folder     Folder to check
     * @param  string $target     Placeholder to inject partial before
     * @return void
     */
    private static function generateSecondLevelBlock($root_block, $row_name, $folder, $target)
    {
        $row = self::locateBlock($root_block, $row_name);
        $blocks = self::findMissingBlocks($row, $folder);

        array_walk($blocks, function ($block, $key) use ($folder, $target) {
            self::createBlock($block, $folder);
            self::createPartial($block, $folder);
            self::appendTargetedPartial($block, $folder, 'blocks/_content_with_sidebar.scss', $target);
        });
    }

    /**
     * Locate a single block
     * @param  array  $data  Array to look through
     * @param  string $block Name to be searched
     * @return array         Located item
     */
    private static function locateBlock($data, $block)
    {
        $found_block = array_filter($data, function ($item) use ($block) {
            return $item['name'] == $block;
        });

        // Reset array keys
        return array_values($found_block);
    }

    /**
     * Generate a list of missing blocks
     * @param  array  $data   ACF flexible field
     * @param  string $folder Block path
     * @return array          Missing blocks
     */
    private static function findMissingBlocks($data, $folder)
    {
        $blocks = array_filter($data[0]['layouts'], function ($item) use ($folder) {
            return !file_exists(BASE . '/' . $folder . '/' . $item['name'] . '.php');
        });

        // No missing blocks
        if (empty($blocks)) {
            return [];
        }

        return self::getBlockNames($blocks);
    }

    /**
     * Extract just block names from missing array
     * @param  array $blocks Blocks
     * @return array         Block names
     */
    private static function getBlockNames($blocks)
    {
        return array_map(function ($layout) {
            return $layout['name'];
        }, $blocks);
    }

    /**
     * Clone default block
     * @param  string $block Block name
     * @return void
     */
    private static function cloneBlock($block)
    {
        $template = file_get_contents(BASE . '/blocks/default_block.php');
        $template = str_replace('default-block', self::convertBlockName($block), $template);

        file_put_contents(BASE . '/blocks/' . $block . '.php', $template);
    }

    /**
     * Clone default block partial
     * @param  string $block Block name
     * @return void
     */
    private static function clonePartial($block)
    {
        $template = file_get_contents(BASE . '/src/scss/blocks/_default_block.scss');
        $template = str_replace('default-block', self::convertBlockName($block), $template);

        file_put_contents(BASE . '/src/scss/blocks/_' . $block . '.scss', $template);
    }

    /**
     * Create PHP block
     * @param  string $block  Block name
     * @param  string $folder Folder path
     * @return void
     */
    private static function createBlock($block, $folder = 'blocks')
    {
        $template  = '<div class="' . self::convertBlockName($block) . '">' . PHP_EOL;
        $template .= '    <!-- Code -->' . PHP_EOL;
        $template .= '</div>';

        file_put_contents(BASE . '/' . $folder . '/' . $block . '.php', $template);
    }

    /**
     * Create SCSS partial
     * @param  string $block  Block name
     * @param  string $folder Folder path
     * @return void
     */
    private static function createPartial($block, $folder = 'blocks')
    {
        $template  = '.' . self::convertBlockName($block) . ' {' . PHP_EOL;
        $template .= '    //' . PHP_EOL;
        $template .= '}';

        file_put_contents(BASE . '/src/scss/' . $folder . '/_' . $block . '.scss', $template);
    }

    /**
     * Append partial to end of stylesheet
     * @param  string $block Block name
     * @return void
     */
    private static function appendPartial($block)
    {
        file_put_contents(BASE . '/src/scss/style.scss', '@import "blocks/' . $block . '";' . PHP_EOL, FILE_APPEND);
    }

    /**
     * Append partial to end of stylesheet
     * @param  string $block  Block name
     * @param  string $folder Folder of partial
     * @param  string $file   Where to append partial
     * @param  string $target Placeholder to place partial before
     * @return void
     */
    private static function appendTargetedPartial($block, $folder, $file, $target)
    {
        $partial = file_get_contents(BASE . '/src/scss/' . $file);
        $folder = substr($folder, 7);
        $import = '@import "' . $folder . '/' . $block . '";';

        $partial = str_replace("/* " . $target . " */", $import . PHP_EOL . "        /* " . $target . " */", $partial);
        file_put_contents(BASE . '/src/scss/' . $file, $partial);
    }

    /**
     * Convert underscores to hyphens
     * @param  string $name Block name
     * @return string       Block name
     */
    private static function convertBlockName($name)
    {
        return str_replace("_", "-", $name);
    }
}
