<?php

namespace Soft_Tehnica\Freya_Sync_Service\Services;

use Soft_Tehnica\Freya_Sync_Service\Data\FSSResponse;
use Soft_Tehnica\Freya_Sync_Service\Data\Location;
use wpdb;

class LocationService
{
    static LocationService $instance;

    /**
     * @return Location[]
     */
    public function getAvaliableLocations(): array
    {
        $fetched = $this->getApiLocations();
        $local = $this->getLocalLocations();

        return array_filter($fetched, function (Location $location) use ($local) {
            foreach ($local as $localLocation) {
                if ($localLocation['uid'] === $location->uid) {
                    return true;
                }
            }

            return false;
        });
    }

    /**
     * @return array<int, array{uid: string, name: string}>
     */
    private function getLocalLocations(): array
    {
        /** @var wpdb $wpdb */
        global $wpdb;
        /** @var array<int, array{uid: string, name: string}> $locations */
        $locations = $wpdb->get_results(
            "SELECT DISTINCT name.meta_value AS name, uid.meta_value AS uid FROM $wpdb->postmeta uid
            INNER JOIN $wpdb->postmeta name
            INNER JOIN $wpdb->posts posts on uid.post_id = posts.ID
            WHERE uid.post_id = name.post_id
            AND posts.post_type = 'product'
            AND uid.meta_key = 'location_uid'
            AND name.meta_key = 'location_name'",
            ARRAY_A
        );

        $locationExt = $wpdb->get_results(
            "SELECT meta.meta_value AS value FROM $wpdb->postmeta meta
            INNER JOIN $wpdb->posts posts ON meta.post_id = posts.ID
            WHERE posts.post_type = 'product'
            AND meta.meta_key = 'location_ext'"
        );

        if (is_null($locationExt)) {
            return $locations;
        }

        foreach ($locationExt as $loc) {
            /** @var array<string, array{name: string, price: float}>|false $ext */
            $ext = unserialize($loc->value);

            if (!$ext) {
                continue;
            }

            foreach ($ext as $uid => $value) {
                $found = false;
                foreach ($locations as $l) {
                    if ($l['uid'] === $uid) {
                        $found = true;
                        break;
                    }
                }

                if ($found) {
                    continue;
                }

                $locations[] = ['uid' => $uid, 'name' => $value['name']];
            }
        }

        return $locations;
    }

    private function fetchLocations(int $page = 1): FSSResponse
    {
        $companyUid = PluginSettings::get()->getCompanyUid();
        return makeHttpGet("api/wp/locations?page=$page&perPage=50&companyUid=$companyUid");
    }

    /**
     * @return Location[]
     */
    private function getApiLocations(): array
    {
        $companyUid = PluginSettings::get()->getCompanyUid();
        if (is_null($companyUid) || strlen($companyUid) === 0) {
            return [];
        }

        $ret = [];
        $page = 0;
        do {
            $page++;
            $res = $this->fetchLocations($page);
            if (!$res->status) {
                break;
            }
            foreach ($res->payload->data as $location) {
                // Validăm că sunt valabile locațiile pentru WP
                if (
                    !$location->isActive
                    || !$location->allowEcommerce
                    || (!$location->hasDelivery && !$location->hasPickup)
                ) {
                    continue;
                }

                $ret[] = new Location(
                    $location->name,
                    $location->uid,
                    $location->isActive,
                    $location->hasDelivery,
                    $location->hasPickup
                );
            }
        } while ($page !== $res->payload->last_page);
        return $ret;
    }

    public static function get(): LocationService
    {
        if (!isset(static::$instance)) {
            static::$instance = new LocationService();
        }
        return static::$instance;
    }
}