<?php

namespace Ignite\Core\Models\Grid;

use Illuminate\Support\Carbon;
use Ignite\Core\Facades\Format;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Traits\Macroable;

class Formatter
{
    use Macroable;

    /**
     * Custom the typical html for buttons.
     *
     * @param  array $actions
     * @return string
     */
    public function buttons($actions)
    {
        $first = array_shift($actions);
        $button = $this->buttonFromArray($first);

        $links = [];
        foreach ($actions as $action) {
            $links[] = sprintf('<li>%s</li>', $this->linkFromArray($action));
        }

        $dropdownButton = sprintf(
            '<button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="caret"></span></button>'
        );
        $dropdown = sprintf('<ul class="dropdown-menu">%s</ul>', implode(PHP_EOL, $links));

        $wrapper = sprintf(
            '<div class="btn-group">%s%s%s</div>',
            $button,
            count($links) ? $dropdownButton : '',
            count($links) ? $dropdown : ''
        );

        return trim(preg_replace('/\s+/', ' ', $wrapper));
    }

    /**
     * Create a button from an array of expected keys.
     *
     * @param  array $button
     * @return string
     */
    public function buttonFromArray($button)
    {
        if (is_null($button)) {
            return '';
        }

        $button = $this->htmlCreateNulls($button);

        return $this->button(
            $button['label'],
            $button['link'],
            $button['type'],
            $button['text'],
            $button['icon'],
            $button['class'],
            $button['click']
        );
    }

    /**
     * Create a link from an array of expected keys.
     *
     * @param  array $link
     * @return string
     */
    public function linkFromArray($link)
    {
        $link = $this->htmlCreateNulls($link);

        return $this->link(
            $link['label'],
            $link['link'],
            $link['type'],
            $link['text'],
            $link['icon'],
            $link['class'],
            $link['click']
        );
    }

    /**
     * Create null values for any key without a value.
     *
     * @param array $data
     * @return array
     */
    public function htmlCreateNulls(array $data)
    {
        $keys = ['label', 'link', 'type', 'text', 'icon', 'class', 'click'];

        foreach ($keys as $key) {
            if (! array_key_exists($key, $data)) {
                $data[$key] = '';
            }
        }

        return $data;
    }

    /**
     * Create a button for the grid.
     *
     * @param  string $label
     * @param  string $link
     * @param  string $type
     * @param  string $text
     * @param  string $icon
     * @param  string $class
     * @param  string $click
     * @return string
     */
    public function button($label, $link, $type = 'default', $text = '', $icon = '', $class = '', $click = '')
    {
        $type = empty($type) ? 'default' : $type;
        $text = empty($text) ? null : $text;
        $class = trim($class . ' btn-' . str_slug($label));

        return sprintf(
            '<a href="%s" class="btn btn-sm btn-%s %s"%s><span class="%s">%s%s</span></a>',
            $link ?? '',
            $type ?? '',
            $class ?? '',
            empty($click) ? '' : " data-message='$click'",
            $text ?? '',
            empty($icon) ? '' : sprintf('<i class="fa fa-%s"></i> ', $icon),
            $label ?? ''
        );
    }

    /**
     * Create a link for the grid or dropdown.
     *
     * @param  string $label
     * @param  string $link
     * @param  string $type
     * @param  string $text
     * @param  string $icon
     * @param  string $class
     * @param  string $click
     * @return string
     */
    public function link($label, $link, $type = 'default', $text = '', $icon = '', $class = '', $click = '')
    {
        $type = empty($type) ? 'default' : $type;
        $text = empty($text) ? null : $text;
        $class = $class . ' ' . str_slug($label);

        return sprintf(
            '<a href="%s" class="%s %s"%s><span class="%s">%s%s</span></a>',
            $link ?? '',
            $type ?? '',
            $class ?? '',
            empty($click) ? '' : " data-message='$click'",
            $text ?? '',
            empty($icon) ? '' : sprintf('<i class="fa fa-%s"></i> ', $icon),
            $label ?? ''
        );
    }

    /**
     * Format the status column.
     *
     * @param  object $model
     * @return HtmlString
     */
    public function status($model)
    {
        return $this->html(ucwords(strtolower($model->status)));
    }

    /**
     * Format the created at column.
     *
     * @param  object $model
     * @return HtmlString
     */
    public function createdAt($model)
    {
        return $this->formatDate($model, 'created_at', 'Y-m-d H:i:s');
    }

    /**
     * Format the updated at column.
     *
     * @param  object $model
     * @return HtmlString
     */
    public function updatedAt($model)
    {
        return $this->formatDate($model, 'updated_at', 'Y-m-d H:i:s');
    }

    /**
     * Format the deleted at column.
     *
     * @param  object $model
     * @return HtmlString
     */
    public function deletedAt($model)
    {
        return $this->formatDate($model, 'deleted_at', 'Y-m-d H:i:s');
    }

    /**
     * Check if a value is falsy and return No or Yes if truthy.
     *
     * @param  mixed $value
     * @return string
     */
    public function formatYesNo($value)
    {
        return ! $value ? trans('Core::core.common.no') : trans('Core::core.common.yes');
    }

    /**
     * Format a number for the grid.
     *
     * @param  object $model
     * @param  string $key
     * @param  int    $decimals
     * @return HtmlString
     */
    public function formatNumber($model, $key, $decimals = 0)
    {
        return Format::amount($model->$key, $decimals);
    }

    /**
     * Format a amount for the grid.
     *
     * @param  object $model
     * @param  string $key
     * @return HtmlString|string
     */
    public function formatAmount($model, $key)
    {
        if (is_object($model) && property_exists($model, $key)) {
            return Format::amount($model->$key);
        }

        return $model;
    }

    /**
     * Format an amount with a currency.
     *
     * @param object $model
     * @param string $key
     * @param int    $decimals
     * @return string
     */
    public function formatCurrency($model, $key, $decimals = 2)
    {
        return Format::currency($model->$key, $decimals);
    }

    /**
     * Format a number with a percentage.
     *
     * @param object $model
     * @param string $key
     * @param int    $decimals
     * @return string
     */
    public function formatPercentage($model, $key, $decimals = 2)
    {
        return $this->formatNumber($model, $key, $decimals) . '%';
    }

    /**
     * Format a date for the grid.
     *
     * @param  object $model
     * @param  string $key
     * @param  string $format
     * @param  string $from
     * @return HtmlString
     */
    public function formatDate($model, $key, $format = 'Y-m-d', $from = 'Y-m-d H:i:s')
    {
        if (! isset($model->$key)) {
            return $this->html('');
        }

        $date = $model->$key;

        if (! $date instanceof Carbon) {
            $date = Carbon::createFromFormat($from, $date, config('app.timezone'));
        }

        return $this->html($date->format($format));
    }

    /**
     * Format a checkbox for the grid.
     *
     * @param  int $id
     * @return HtmlString
     */
    public function formatCheckbox($id)
    {
        return $this->html(sprintf(
            '<input type="checkbox" class="dt-checkboxes" name="entries[]" value="%s" />',
            $id
        ));
    }

    /**
     * Format the value as a HTML string.
     *
     * @param  string $value
     * @return HtmlString
     */
    public function html($value)
    {
        return new HtmlString($value);
    }
}
