<?php

namespace EstatebudConnect\Models;

if (!defined('WPINC')) {
    die();
}

use EstatebudConnect\Configs\Property as Config;
use EstatebudConnect\Configs\Defaults;
use EstatebudConnect\Core\OptionsAPI;
use EstatebudConnect\Core\Cache;
use EstatebudConnect\Services\Estatebud;
use EstatebudConnect\Utilities\Helper;
use EstatebudConnect\Interfaces\Listing as ListingInterface;

class Property implements ListingInterface
{
    public $id;
    public $external_id;
    public $source;
    public $branch_id;
    public $location_lat;
    public $location_lng;
    public $location_accuracy;
    public $owner_id;
    public $owner_type;
    public $buyer;
    public $tenant;
    public $category;
    public $type;
    public $street;
    public $zipcode;
    public $city;
    public $country;
    public $area_id;
    public $featured;
    public $created_time;
    public $updated_time;
    public $area1_id;
    public $area1_name;
    public $area2_id;
    public $area2_name;
    public $area3_id;
    public $area3_name;
    public $reference_id;
    public $status;
    public $floor;
    public $subcategories;
    public $furnished;
    public $basement;
    public $titledeed;
    public $roadaccess;
    public $structure;
    public $facade;
    public $framestype;
    public $orientation;
    public $emphyteusis;
    public $communalcharge;
    public $groundrent;
    public $suma;
    public $areas;
    public $data;
    public $price;
    public $rent;
    public $title;
    public $description;
    public $originalprice;
    public $originalrent;
    public $labels;
    public $facilities;
    public $features;
    public $distances;
    public $zones;
    public $project_summary;
    public $blocks;
    public $images;
    public $floorplans;
    public $videos;
    public $branch;
    public $agents;
    public $plugins;
    public $public;
    public $matching;

    public function __construct(array $data = [])
    {
        if (isset($data['error'])) {
            throw new \Exception('Failed to initialize ' . esc_html(get_class($this)) . ': ' . esc_html($data['error'] ?? 'Unknown error'));
        }
        
        $this->id = $data['id'] ?? null;
        $this->external_id = $data['external_id'] ?? null;
        $this->source = $data['source'] ?? null;
        $this->branch_id = $data['branch_id'] ?? null;
        $this->location_lat = $data['location_lat'] ?? null;
        $this->location_lng = $data['location_lng'] ?? null;
        $this->location_accuracy = $data['location_accuracy'] ?? null;
        $this->owner_id = $data['owner_id'] ?? null;
        $this->owner_type = $data['owner_type'] ?? null;
        $this->buyer = $data['buyer'] ?? null;
        $this->tenant = $data['tenant'] ?? null;
        $this->category = $data['category'] ?? null;
        $this->type = $data['type'] ?? null;
        $this->street = $data['street'] ?? null;
        $this->zipcode = $data['zipcode'] ?? null;
        $this->city = $data['city'] ?? null;
        $this->country = $data['country'] ?? null;
        $this->area_id = $data['area_id'] ?? null;
        $this->featured = $data['featured'] ?? null;
        $this->created_time = $data['created_time'] ?? null;
        $this->updated_time = $data['updated_time'] ?? null;
        $this->area1_id = $data['area1_id'] ?? null;
        $this->area1_name = $data['area1_name'] ?? null;
        $this->area2_id = $data['area2_id'] ?? null;
        $this->area2_name = $data['area2_name'] ?? null;
        $this->area3_id = $data['area3_id'] ?? null;
        $this->area3_name = $data['area3_name'] ?? null;
        $this->reference_id = $data['reference_id'] ?? null;
        $this->status = $data['status'] ?? null;
        $this->floor = $data['floor'] ?? null;
        $this->subcategories = $data['subcategories'] ?? [];
        $this->furnished = $data['furnished'] ?? null;
        $this->basement = $data['basement'] ?? null;
        $this->titledeed = $data['titledeed'] ?? null;
        $this->roadaccess = $data['roadaccess'] ?? null;
        $this->structure = $data['structure'] ?? null;
        $this->facade = $data['facade'] ?? null;
        $this->framestype = $data['framestype'] ?? null;
        $this->orientation = $data['orientation'] ?? null;
        $this->emphyteusis = $data['emphyteusis'] ?? null;
        $this->communal_charge = $data['communal_charge'] ?? null;
        $this->ground_rent = $data['ground_rent'] ?? null;
        $this->suma = $data['suma'] ?? null;
        $this->areas = $data['areas'] ?? [];
        $this->data = $data['data'] ?? null;
        $this->price = $data['price'] ?? null;
        $this->rent = $data['rent'] ?? null;
        $this->title = $data['title'] ?? null;
        $this->description = $data['description'] ?? null;
        $this->originalprice = $data['originalprice'] ?? null;
        $this->originalrent = $data['originalrent'] ?? null;
        $this->labels = $data['labels'] ?? [];
        $this->facilities = $data['facilities'] ?? [];
        $this->features = $data['features'] ?? [];
        $this->distances = $data['distances'] ?? [];
        $this->zones = $data['zones'] ?? [];
        $this->project_summary = $data['project_summary'] ?? [];
        $this->blocks = $data['blocks'] ?? [];
        $this->images = $data['images'] ?? [];
        $this->floorplans = $data['floorplans'] ?? [];
        $this->videos = $data['videos'] ?? [];
        $this->branch = $data['branch'] ?? null;
        $this->agents = $data['agents'] ?? [];
        $this->plugins = $data['plugins'] ?? [];
        $this->public = (bool) ($data['public'] ?? false);
        $this->matching = (bool) ($data['matching'] ?? false);
    }

    public function get_id()
    {
        return $this->id;
    }

    public function get_image()
    {
        foreach ($this->images as $image) {
            if ($image['status'] == '1') {
                $url = $image['url'];
                break;
            }
        }

        return $url ?? Helper::get_url('assets/images/listing-placeholder.png');
    }

    public function get_images()
    {
        $images = [];

        foreach ($this->images as $image) {
            if ($image['status'] == '1') {
                $images[] = [
                    'url' => $image['url'],
                ];
            }
        }

        return $images;
    }

    public function get_floorplans()
    {
        $floorplans = [];

        foreach ($this->floorplans as $floorplan) {
            if ($floorplan['status'] == '1') {
                $floorplans[] = [
                    'url' => $floorplan['url'],
                ];
            }
        }

        return $floorplans;
    }

    public function get_videos()
    {
        $videos = [];

        foreach ($this->videos as $video) {
            $thumbnail = null;

            if ($video['platform'] === 'youtube') {
                $thumbnail = sprintf("https://i.ytimg.com/vi/%s/mqdefault.jpg", $video['platform_id']);
            }

            $videos[] = [
                'platform' => $video['platform'],
                'platform_id' => $video['platform_id'],
                'url' => $video['url'],
                'thumbnail' => $thumbnail ?? $this->get_image()
            ];
        }

        return $videos;
    }

    public function get_virtual_tours()
    {
        $virtual_tours = [];

        foreach ($this->plugins as $plugin => $data) {
            if (isset($data['virtualtour'])) {
                $virtual_tours[] = [
                    'plugin' => $plugin,
                    'url' => $data['virtualtour'],
                    'thumbnail' => $this->get_image(),
                ];
            }
        }

        return $virtual_tours;
    }

    public function get_coordinates()
    {
        if (empty($this->location_lat) || empty($this->location_lng)) {
            return false;
        }
        
        return [
            'lat' => $this->location_lat,
            'lng' => $this->location_lng,
        ];
    }

    public function get_price()
    {
        $price_data = $this->price ?? $this->rent;

        if (!is_array($price_data) || empty($price_data)) {
            return [
                'price' => 0,
                'vat' => false,
                'currency' => null,
            ];
        }

        $currency = key($price_data);
        $price_info = $price_data[$currency];

        $price = $price_info['amount'] ?? 0;
        $vat = $price_info['vat'] ?? false;
        $frequency = $this->data['rentfrequency'] ?? '';
        $symbol = $price_info['details']['symbol'] ?? '';

        if (empty($frequency) && $this->is_rental()) {
            $frequency = 'month';
        }

        return [
            'price' => (float) $price,
            'vat' => (bool) $vat,
            'frequency' => $frequency,
            'currency' => $currency,
            'symbol' => $symbol,
        ];
    }

    public function get_original_price()
    {
        $price_data = $this->originalprice;

        if (!is_array($price_data) || empty($price_data)) {
            return null;
        }

        $currency = key($price_data);
        $price_info = $price_data[$currency];

        $price = $price_info['amount'] ?? null;
        $vat = $price_info['vat'] ?? false;
        $symbol = $price_info['details']['symbol'] ?? '';

        return [
            'price' => (float) $price,
            'vat' => (bool) $vat,
            'currency' => $currency,
            'symbol' => $symbol,
        ];
    }

    public function get_labels()
    {
        $labels = [];

        if ($this->featured == '1') {
            $labels[] = [
                'id' => null,
                'name' => 'Featured',
                'color' => '#050505',
            ];
        }

        if ($this->is_sold()) {
            $labels[] = [
                'id' => null,
                'name' => 'Sold',
                'color' => '#DC2626',
            ];
        }

        if ($this->is_rented()) {
            $labels[] = [
                'id' => null,
                'name' => 'Rented',
                'color' => '#DC2626',
            ];
        }

        if (isset($this->labels)) {
            foreach ($this->labels as $label) {
                if ($label['public'] != '1') {
                    continue;
                }

                $labels[] = [
                    'id' => $label['id'],
                    'name' => $label['name'],
                    'color' => '#' . $label['color'],
                ];
            }
        }

        return $labels;
    }

    public function get_reference_id()
    {
        return $this->reference_id;
    }

    public function get_bedrooms()
    {
        if (!isset($this->data['bedrooms'])) {
            return null;
        }

        return $this->data['bedrooms'] == '0' ? Helper::term('listing.bedrooms.studio') : $this->data['bedrooms'];
    }

    public function get_bathrooms()
    {
        if (!isset($this->data['bathrooms'])) {
            return null;
        }

        return $this->data['bathrooms'];
    }

    public function get_covered_area()
    {
        if (!isset($this->areas['coveredm2'])) {
            return null;
        }

        return $this->areas['coveredm2']['value'] . ' m²';
    }

    public function get_plot_area()
    {
        if (!isset($this->areas['plotm2'])) {
            return null;
        }

        return $this->areas['plotm2']['value'] . ' m²';
    }

    public function get_type($language = null)
    {
        $type = Helper::get_term_from_array($this->type, $language);

        if (empty($type)) {
            $type = 'Property';
        }

        return $type;
    }

    public function get_area()
    {
        $area = [];
        if (!empty($this->area3_name ?? '')) {
            $area[] = $this->area3_name;
        }
        if (!empty($this->area2_name ?? '')) {
            $area[] = $this->area2_name;
        }
        if (!empty($this->area1_name ?? '')) {
            $area[] = $this->area1_name;
        }

        return count($area) ? implode(', ', $area) : null;
    }

    public function get_title($language = null)
    {
        $title = Helper::get_term_from_array($this->title, $language);

        if (empty($title)) {
            $title = $this->generate_title($language);
        }

        return $title;
    }

    public function get_slug($language = null)
    {
        $title = $this->get_title($language);
        $slug = Helper::slugify($title);

        return $slug;
    }

    public function get_attributes()
    {
        $estatebud_field_options = Estatebud::instance()
            ->cache(Cache::TTL_1MO)
            ->get_fields(['component' => 'property']);
        $estatebud_field_names = array_column($estatebud_field_options, 'name');

        $whois = Estatebud::instance()->cache(Cache::TTL_1H)->whois();
        $currency = strtolower($whois['currency'] ?? '');

        $possible_attributes = Config::ATTRIBUTES;
        $attributes = [];

        foreach ($possible_attributes as $possible_attribute) {
            $name = $possible_attribute['name'];
            $icon = $possible_attribute['icon'];
            $estatebud_field_name = null;
            $value = null;
            $label = null;

            if ($name == 'energyefficiencyrating' && in_array($this->data[$name] ?? '', ['pending', 'exempt'])) {
                if ($this->data[$name] == 'pending') {
                    $value = 'Pending';
                } elseif ($this->data[$name] == 'exempt') {
                    $value = 'Exempt';
                }
            } else if (isset($this->$name[$currency]['amount'])) {
                $value = $this->$name[$currency]['amount'];
            } else if (isset($this->$name['translations'])) {
                $value = Helper::get_term_from_array($this->$name);
            } else if (!empty($this->$name) && is_array($this->$name)) {
                $values = [];

                foreach ($this->$name as $item) {
                    $values[] = Helper::get_term_from_array($item);
                }

                $value = implode(', ', $values);
            } else if (isset($this->data[$name]) && !is_array($this->data[$name])) {
                $value = $this->data[$name];
            }

            if ($name == 'ground_rent') {
                $value = Helper::format_price(['price' => $value, 'currency' => $currency]);
                $estatebud_field_name = "groundrent" . $currency;
            }

            if ($name == 'suma') {
                $value = Helper::format_price(['price' => $value, 'currency' => $currency]);
                $estatebud_field_name = "suma" . $currency;
            }

            if ($name == 'communal_charge') {
                $value = Helper::format_price(['price' => $value, 'currency' => $currency]);
                $estatebud_field_name = "communalcharge" . $currency;

                if(!empty($this->data['communalchargefrequency'])) {
                    $value .= ' ' . Helper::term('frequency.every.' . $this->data['communalchargefrequency']);
                }
            }

            if (!is_null($value)) {
                if (is_null($label) && $key = array_search($estatebud_field_name ?? $name, $estatebud_field_names)) {
                    $label = $estatebud_field_options[$key]['label'];
                }

                if (!is_null($label)) {
                    $attributes[] = [
                        'name' => $name,
                        'label' => $label,
                        'icon' => $icon,
                        'value' => $value
                    ];
                }
            }
        }

        return $attributes;
    }

    public function get_facilities()
    {
        $facilites = [];
        foreach ($this->facilities as $item) {
            $facilites[] = [
                'value' => Helper::get_term_from_array($item) . ($item['value'] != '1' ? ', '.$item['value'] : '')
            ];
        }

        return $facilites;
    }

    public function get_features()
    {
        $features = [];
        foreach ($this->features as $item) {
            $features[] = [
                'value' => Helper::get_term_from_array($item)
            ];
        }

        return $features;
    }

    public function get_distances()
    {
        $estatebud_field_options = Estatebud::instance()
            ->cache(Cache::TTL_1MO)
            ->get_fields(['component' => 'property']);
        $estatebud_field_names = array_column($estatebud_field_options, 'name');

        $possible_distances = Config::DISTANCES;
        $distances = [];

        foreach ($possible_distances as $possible_distance) {
            $name = $possible_distance['name'];
            $icon = $possible_distance['icon'];
            $value = null;

            if (!empty($this->distances[$name])) {
                $unit = str_contains($name, 'km') ? 'km' : 'mi';
                $value = Helper::convert_distance($unit, $this->distances[$name]['value']);
            }

            if (!is_null($value)) {
                $label = null;

                if ($key = array_search($name, $estatebud_field_names)) {
                    $label = $estatebud_field_options[$key]['label'];
                }

                $distances[] = [
                    'name' => $name,
                    'label' => $label,
                    'icon' => $icon,
                    'value' => $value
                ];
            }
        }

        return $distances;
    }

    public function get_areas()
    {
        $estatebud_field_options = Estatebud::instance()
            ->cache(Cache::TTL_1MO)
            ->get_fields(['component' => 'property']);
        $estatebud_field_names = array_column($estatebud_field_options, 'name');

        $possible_areas = Config::AREAS;
        $areas = [];
        
        foreach ($possible_areas as $possible_area) {
            $name = $possible_area['name'];
            $icon = $possible_area['icon'];
            $value = null;

            if (!empty($this->areas[$name]['value'])) {
                $value = number_format_i18n($this->areas[$name]['value']) . ' m²';
            }

            if (!is_null($value)) {
                $label = null;

                if ($key = array_search($name, $estatebud_field_names)) {
                    $label = $estatebud_field_options[$key]['label'];
                }

                $areas[] = [
                    'name' => $name,
                    'label' => $label,
                    'icon' => $icon,
                    'value' => $value
                ];
            }
        }

        return $areas;
    }

    public function get_planning_zones()
    {
        $planning_zones = [];

        foreach ($this->zones as $item) {
            $planning_zones[] = [
                'code' => $item['code'] ?? '-',
                'cover_factor' => isset($item['cover_factor']) ? $item['cover_factor'] . '%' : '-',
                'build_factor' => isset($item['build_factor']) ? $item['build_factor'] . '%' : '-',
                'max_height' => isset($item['max_height']) ? $item['max_height'] . ' m' : '-',
                'max_floors' => isset($item['max_floors']) ? $item['max_floors'] : '-',
                'affected_percentage' => isset($item['affected_percentage']) ? $item['affected_percentage'] . '%' : '-'
            ];
        }

        return $planning_zones;
    }

    public function get_units()
    {
        return false;
    }

    public function get_page_title()
    {
        $sep = apply_filters('document_title_separator', '&#8211;');

        return $this->get_title() . ' ' . $sep . ' ' . get_bloginfo('name');
    }

    public function get_meta_description()
    {
        $text = Helper::get_term_from_array($this->description);
        $text = str_replace(["\r", "\n"], ' ', $text);
        $text = preg_replace('/\s+/', ' ', $text);
        $text = mb_substr($text, 0, 200);

        return $text;
    }

    public function get_og_image()
    {
        return $this->get_image();
    }

    public function get_og_title()
    {
        return $this->get_page_title();
    }

    public function get_og_url($language = null)
    {
        return $this->get_url($language);
    }

    public function get_og_description()
    {
        return $this->get_meta_description();
    }

    public function get_url($language = null)
    {
        return Helper::home_url('/' . Helper::slugify(Helper::term('property', 1, $language)) . '/' . $this->get_reference_id() . '/' . trim($this->get_slug($language), '-') . '/', $language);
    }

    public function generate_title($language = null)
    {
        $active_language = Helper::get_locale();

        if (is_null($language)) {
            $language = $active_language;
        }

        if (in_array($this->category, ['res_sale', 'res_rent_long', 'res_rent_short']) && $this->get_bedrooms() && !empty($this->type)) {
            $title = sprintf(Helper::term('listing.generate_title.x_bedroom_x', $this->get_bedrooms(), $language), $this->get_bedrooms(), Helper::get_term_from_array($this->type, $language));
        } elseif (in_array($this->category, ['res_sale', 'com_sale', 'land'])) {
            $title = sprintf(Helper::term('listing.generate_title.x_for_sale', 1, $language), Helper::term('property', 1, $language));
        } elseif (in_array($this->category, ['res_rent_long', 'res_rent_short'])) {
            $title = sprintf(Helper::term('listing.generate_title.x_to_rent', 1, $language), Helper::term('property', 1, $language));
        }

        $title =
            mb_substr(mb_strtoupper($title ?? '', 'UTF-8'), 0, 1, 'UTF-8') .
            mb_substr(mb_strtolower($title ?? '', 'UTF-8'), 1, null, 'UTF-8');

        return $title;
    }

    public function is_matching_enabled()
    {
        return $this->matching;
    }

    public function is_published()
    {
        return $this->public || $this->matching;
    }

    public function is_rental()
    {
        return str_contains($this->category, 'rent');
    }

    public function is_sold()
    {
        return isset($this->buyer);
    }

    public function is_rented($offset = 0)
    {
        $settings = $this->get_settings();

        $availability_offset = $settings['availability_offset'];

        if (!empty($this->tenant['period_to']) && !empty($availability_offset)) {
            $adjusted_availability_date = strtotime($this->tenant['period_to']) - $availability_offset;

            return current_time('U') < $adjusted_availability_date;
        }

        return isset($this->tenant);
    }

    public function get_settings()
    {
        $result = OptionsAPI::instance()->get('property_listing');

        if ($result) {
            return array_merge(Defaults::PROPERTY_LISTING, $result);
        } else {
            return Defaults::PROPERTY_LISTING;
        }
    }

    public function save_settings($form_data)
    {
        $defaults = Defaults::PROPERTY_LISTING;
        $textareas = ['legal_disclaimer'];
        $booleans = ['mortgage_calculator','similar_properties','brochure_show_agent','brochure_white_label','show_availability_date'];

        $parsed_form_data = [];

        foreach ($form_data as $key => $value) {
            $key = sanitize_text_field(wp_unslash($key));
            $value = wp_unslash($value);

            if (isset($defaults[$key])) {
                if (in_array($key, $booleans)) {
                    $value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
                } else if (in_array($key, $textareas)) {
                    $value = sanitize_textarea_field($value);
                } else {
                    $value = sanitize_text_field($value);
                }

                $parsed_form_data[$key] = $value;
            }
        }

        $result = OptionsAPI::instance()->update('property_listing', $parsed_form_data);
        
        return $result;
    }
}
