<?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
{

    public static LocationService $instance;

    private const TRANSIENT_KEY = 'fss_api_locations';
    private const TRANSIENT_TTL = 300; // 5 minutes

    private static ?array $availableLocationsCache = null;

    /**
     * @return Location[]
     */
    public function getAvaliableLocations(): array
    {
        if ( static::$availableLocationsCache !== null ) {
            return static::$availableLocationsCache;
        }

        $fetched = $this->getApiLocations();
        $local = $this->getLocalLocations();

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

            return false;
        } ) );

        return static::$availableLocationsCache;
    }

    public function clearCache(): void
    {
        static::$availableLocationsCache = null;
        delete_transient( self::TRANSIENT_KEY );
    }

    /**
     * @return array<int, array{uid: string, name: string}>
     */
    private function getLocalLocations(): array
    {
        global $wpdb;
        /** @var wpdb $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 wp_posts posts
                INNER JOIN wp_postmeta uid  ON uid.post_id = posts.ID
                INNER JOIN wp_postmeta name ON name.post_id = posts.ID
                WHERE 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 [];
        }

        $transientKey = self::TRANSIENT_KEY;
        $cached = get_transient( $transientKey );

        if ( $cached !== false ) {
            return $cached;
        }

        $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 );

        set_transient( $transientKey, $ret, self::TRANSIENT_TTL );

        return $ret;
    }

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

        return static::$instance;
    }
}
