<?php
/**
 * @package    pixelcms_articles
 *
 * @author     christophf <your@email.com>
 * @copyright  A copyright
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 * @link       http://your.url.com
 */

use Joomla\Registry\Registry;

defined('_JEXEC') or die;


require_once 'BaseModel.php';

class Adapter {
    function __construct(object $data)
    {
        foreach($data as $key => $val) {

            if(property_exists($this, $key)) {
                $this->$key = utf8_encode($val);
            }
        }
    }
}

class PriceAdapter extends Adapter {
    public $currency;
    public $tax;
    public $special_price;
    public $gross_price;
    public $tax_type;
}

/**
 * @package     Technikboerse
 *
 * @property PriceAdapter $price_meta
 * @since version
 */
class ProductAdapter extends Adapter {
    public $id;
    public $title;
    public $price;
    public $manufacturer;
    public $model;
    public $category_name;
    public $category_id;
    public $manufacturing_date;
    public $horsepower;
    public $kw;
    public $working_hours;
    public $description; // details only
    public $type;
    public $dealer;
    public $mwst_seperate;
    public $mwst_satz;
    public $internal_id;
    public $created_date;

    public function __construct(object $data)
    {
        parent::__construct($data);

        $this->type = ((bool) $data->used === true) ? 'used' : (((bool) $data->new === true) ? 'new' : 'rental');

        $this->created_date = DateTime::createFromFormat('d.m.y', trim($data->created_date)) ?: new DateTime();
    }
}

class Category {
    public $id;
    public $name;

    public function  __construct(ProductAdapter $product) {
        $this->id = $product->category_id;
        $this->name = $product->category_name;
    }
}

class Manufacturer {
    public $id;
    public $value;

    public function  __construct(ProductAdapter $product) {
        $this->value = (string) $product->manufacturer;
        $this->id = hexdec(substr(md5($this->value), 1, 3));
    }
}

class Condition {
    public $id = 'used';

    public function  __construct(ProductAdapter $product) {
        $this->id = $product->type;
    }
}

class Workhours {
    public $unit = 'Std.';
    public $value;
    public $show;

    public function  __construct(ProductAdapter $product) {
        if ($product->working_hours) {
            $this->value = (float) $product->working_hours;
            $this->show = "$this->value $this->unit";
        }
    }
}

class Vat {
    public $value;
    public $separable;

    public function  __construct(ProductAdapter $product) {
        $this->value = (float) $product->mwst_satz / 100;
        $this->separable = $product->mwst_seperate === 'ausweisbar';
    }
}

class Power {
    public $PS;
    public $kW;

    public function  __construct(ProductAdapter $product) {
        $this->PS = (float) $product->horsepower;
        $this->kW = (float) $product->kw ?? round($product->horsepower / 1.36);
    }
}

class Dealer {
    public $id;
    public $name;

    public function  __construct(ProductAdapter $product) {
        $this->id = hexdec(substr(md5($product->dealer), 1, 3));
        $this->name = $product->dealer;
    }
}

class Price {
    public $currency = 'EUR';
    public $specialprice = false;
    public $values;

    public function __construct(ProductAdapter $product)
    {
        $vat = (float) $product->mwst_satz / 100;

        $brutto = (float) str_replace(['.', ','], ['', '.'], $product->price);

        // Only products with prices get calculated
        if ($brutto > 0) {
            $this->values = (object) [
                'brutto' => $brutto,
                'netto' => round($brutto / (1 + $vat)),
            ];
        }
    }
}

class Product {
    private $product;
    public $id;
    public $category;
    public $price;
    public $vat;
    public $properties; // attributes
    public $manufacturer;
    public $model;
    public $year;
    public $power; // optional
    public $workhours; // optional
    public $link;
    public $offer;
    public $images;
    public $free_text; // no
    public $contact_persons; // no
    public $condition;
    public $dealer;
    public $dealer_internal_id;
    public $created_date;

    public function  __construct(ProductAdapter $product) {
        $this->product = $product;
        $this->category = new Category($product);

        $this->id = $product->id;

        $this->images = $this->getImages();

        $this->condition = new Condition($product);

        $this->dealer = new Dealer($product);

        $this->model = $product->model;
        $this->year = $product->manufacturing_date;

        $this->manufacturer = new Manufacturer($product);
        $this->price = new Price($product);
        $this->vat = new Vat($product);

        $this->created_date = $product->created_date->format('d.m.Y');

        if($this->hasProperty('working_hours')) {
            $this->workhours = new Workhours($product);
        }

        if($this->hasProperty('horsepower')) {
            $this->power = new Power($product);
        }

        if ($this->hasProperty('description')) {
            $this->free_text = $product->description;
        }

        $this->dealer_internal_id = $product->internal_id;

        $this->offer = $this->price->specialprice;
    }

    private function hasProperty($prop): bool
    {
        return isset($this->product->{$prop});
    }

    private function getImages(): array
    {
        return array_map(function($image) {
            return (object) ['href' => str_replace(JPATH_BASE . '/', JURI::root(), $image)];
        }, glob(JPATH_BASE . "/maschinen_daten/{$this->id}_*.jpg"));
    }

    public function getSortValue()
    {
        return $this->product->created_date;
    }
}

class Pixelcms_articlesModelCsv_products  extends BaseModel
{
    protected $module = 'traktorpool';
    protected $api_key;
    protected $articleId;
    protected $customer_id;
    protected $contact_persons;
    protected $password;
    protected $username;
    protected $language;
    protected $url;
    protected $ads;
    protected $params;
    protected $allParams;
    protected $menuId;
    protected $filters = [];

    protected $defaults = [
        'print_btn' => 1,
        'price_style' => 0,
        'speed', 750,
        'disable_title_image' => 0,
    ];

    protected $hidden = [
        'tracktorpool_apikey',
        'tracktorpool_customer_id',
        'tracktorpool_username',
        'tracktorpool_password',
        'traktorpool_condition',
        'traktorpool_status',
    ];

    public function __construct(array $config = array())
    {
        $lang = JFactory::getLanguage();
        $langCode = $lang->getTag();
        $langCodeShort = substr($langCode, 0, 2);

        parent::__construct($config);

        /** @var ExtendedRegistry $params - Settings for current Menu Item */
        $params = $this->getState('params');

        $this->menuId = $params->getInt('Itemid');
        $menu = JFactory::getApplication()->getMenu()->getItem($this->menuId);

        $this->params = [];
        $this->allParams = [];
        foreach ($menu->query as $key => $item) {
            if (!in_array($key, $this->hidden)) {
                $this->params[$key] = $item;
            }
            $this->allParams[$key] = $item;
        }

        $this->api_key = $params->get('tracktorpool_apikey');
        $this->customer_id = $params->get('tracktorpool_customer_id');

        //$this->print_btn = $jinput->getInt('print_btn');
        $this->articleId = $params->get('articleId', null);

        $this->language = $langCode;
    }

    private function getAds()
    {
        $ads = self::getCachedAds();

        foreach ($ads as $ad) {
            $query = http_build_query(array_merge($this->params, [
                'articleId' => $ad->id,
                'Itemid' => $this->menuId,
            ]));
            $ad->link = JRoute::_("index.php?$query");
        }

        usort($ads, function(Product $b, Product $a) {
            return $a->getSortValue() <=> $b->getSortValue();
        });

        return $ads;
    }

    public function getRelatedAds()
    {
        $ads = $this->getAds();
        $ad = $this->getData();
        $relatedAds =  array_values(array_filter($ads, function ($relatedAd) use ($ad) {
            return !!($ad->category->id == $relatedAd->category->id && $ad->id != $relatedAd->id);
        }));

        self::fisherYatesShuffle($relatedAds, $ad->id);

        return $relatedAds;
    }

    private static function fisherYatesShuffle(&$items, $seed)
    {
        if (is_string($seed)) {
            mt_srand(crc32($seed));
        } else {
            mt_srand($seed);
        }

        $items = array_values($items);
        for ($i = count($items) - 1; $i > 0; $i--)
        {
            $j = mt_rand(0, $i);
            $tmp = $items[$i];
            $items[$i] = $items[$j];
            $items[$j] = $tmp;
        }
    }

    public function getParams()
    {
        return $this->params;
    }

    /**
     *
     * @return mixed
     *
     * @since version
     * @throws Exception
     */
    private function fetchAds()
    {
        $mapping = [
            'category_id',
            'id',
            'category_name',
            'manufacturer',
            'model',
            'manufacturing_date',
            'working_hours',
            'kw',
            'horsepower',
            'price',
            'mwst_seperate',
            'dealer',
            'description',
            'website',
            'used',
            'new',
            'rental',
            'mwst_satz',
            'internal_id',
            'created_date'
        ];

        $file = file(JPATH_BASE . '/maschinen_daten/maschine.txt');

        return array_map(function($line) use ($mapping) {
            $str = str_getcsv($line, ';');
            $a = array_splice($str,0 , 20);
            return new Product(new ProductAdapter((object) array_combine($mapping, $a)));
        }, array_splice($file, 1));
    }

    private function getCachedAds($force = false)
    {
        $cacheKey = "csv_products.$this->customer_id";
        $ads = $this->cache->get($cacheKey, $this->module);

        if (empty($ads) || $force) {
            $ads = $this->fetchAds();
            $this->cache->store( serialize($ads), $cacheKey, $this->module);
        } else {
            $ads = unserialize($ads);
        }

        return $ads ?? [];
    }

    public function getData()
    {
        $this->ads = $this->getAds();

        if ($this->articleId) {
            $key = array_search($this->articleId, array_column($this->ads, 'id'));

            return $this->ads[$key];
        }
        return $this->ads;
    }
}
