<?php

namespace Hilco\Models;

use DB;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Request;

class WebCollection extends WebModel implements HasLandingPageInterface, HasWebSiloOverridesInterface {
    protected $table = "WebCollections";
    protected $fillable = ['name', 'slug', 'webCategoryIds', 'is_visible', 'detail', 'sort_priority', 'metadata_title', 'metadata_description'];
    protected $casts = [
        ['is_visible' => 'boolean']
    ];
    protected $with = ['webSiloOverride'];
    protected $perPage = 24;

    public static $perEnvironment = true;

    public function getSolrRecord($webSilos) {
        $record = [
            'id' => $this->id,
            'name' => $this->name,
            'slug' => $this->slug,
        ];

        // Add language localized versions of translatable columns
        foreach ($this->translations as $webModelTranslation) {
            $columnName = $webModelTranslation->column_name;
            if ($columnName != 'detail') {
                $language = $webModelTranslation->language;
                $value = $webModelTranslation->translation;
                $transKey = $columnName . '_' . $language; // e.g., 'name_en', 'name_fr'
                $record[$transKey] = $value;
            }
        }

        // Add "searchable" fields with non-alphanumeric characters stripped out of the values
        // /[^A-Za-z0-9\x{00C0}-\x{00FF}\x{1E9E}]/u matches all non-alphanumerics, the 00C0-00FF range of Unicode Latin-1 Supplement characters, and 1E9E (ß) from Unicode Latin Extended Additional
        foreach ($record as $key => $item) {
            $record[$key."_searchable"] = preg_replace("/[^A-Za-z0-9\x{00C0}-\x{00FF}\x{1E9E}]/u", '', $item);
        }

        // Populate list of microsites for which this item should be valid and visible
        $record['webSiloIds'] = [];
        if ($webSilos === null) {
            $webSilos = WebSilo::visible()->get();
        }
        foreach ($webSilos as $webSilo) {
            if ($this->visibleInSilo($webSilo)) $record['webSiloIds'][] = $webSilo->id;
        }

        $hasNonRX = false;
        foreach($this->webFamilies as $webFamily) {
            if ($webFamily->webParts) {
                foreach ($webFamily->webParts as $webPart) {
                    if ($webPart->part && !$webPart->part->is_rx) {
                        $hasNonRX = true;
                        break 2;
                    }
                }
            }
        }
        $record['is_rx'] = !$hasNonRX;
        $record['b2b_web_visible'] = $this->is_solr_visible;

        return $record;
    }

    public function solrTable()
    {
        return $this->hasMany(WebCollection_Solr::class, 'webCollection_id', 'id');
    }

    public function getSolrClassAttribute() {
        return WebCollection_Solr::class;
    }

    public function getSolrIDFieldAttribute() {
        return 'webCollection_id';
    }

    public function getIsSolrVisibleAttribute() {
        return static::solrVisible()->where('id', $this->id)->count() > 0;
    }

    public function scopeSolrVisible(Builder $query) {
        return
            $query
                ->isVisible()
                ->hasSolrVisibleParents()
                ->hasSolrVisibleChildren()
            ;
    }

    public function scopeHasSolrVisibleChildren(Builder $query) {
        return $query
            ->whereHas('webFamilies', function ($query) {
                return $query->isVisible()->hasSolrVisibleChildren();
            })
            ;
    }

    public function scopeHasSolrVisibleParents(Builder $query) {
        return $query
            ->whereHas('webCategories', function ($query) {
                return $query->isVisible()->hasSolrVisibleParents();
            })
            ;
    }

    public function getPerPage()
    {
        $tmpPerPage = Request::input('perPage');
        return (isset($tmpPerPage) && $tmpPerPage > 0)?$tmpPerPage:$this->perPage;
    }

    public function getDisplayNameForUACAttribute() {
        return $this->attributes['name'];
    }

    public function getNameAttribute() {
        if (config('hilco.ignoreActiveWebSilo')) {
            return $this->getTranslation('name', AvailableLanguage::DEFAULT_LANG_CODE, $this->attributes['name']);
        } else {
            if (isset($this->webSiloOverride) &&
                $this->webSiloOverride->is_visible &&
                !is_null($this->webSiloOverride->name) &&
                trim($this->webSiloOverride->name) != '') {

                return $this->webSiloOverride->name;
            } else {
                return $this->getTranslation('name');
            }
        }
    }

    public function getNameForEditAttribute() {
        return $this->getTranslation('name', AvailableLanguage::DEFAULT_LANG_CODE, $this->attributes['name']);
    }

    public function getDetailAttribute() {
        if (config('hilco.ignoreActiveWebSilo')) {
            return $this->getTranslation('detail', AvailableLanguage::DEFAULT_LANG_CODE, $this->attributes['detail']);
        } else {
            if (isset($this->webSiloOverride) &&
                $this->webSiloOverride->is_visible &&
                !is_null($this->webSiloOverride->detail)) {

                return $this->webSiloOverride->detail;
            } else {
                return $this->getTranslation('detail');
            }
        }
    }

    public function webCategories() {
        $returnMe = $this->belongsToMany(WebCategory::class, 'WebCollection_WebCategory', 'webcollection_id', 'webcategory_id')->wherePivot('deleted_at', '=', '0000-00-00 00:00:00')->withPivot('display_order');
        return $returnMe;
    }

    public function webCollectionTranslations(){
        return $this->hasMany(Translations_WebCollection::class, 'webcollection_id', 'id');
    }

    /**
     * @return BelongsToMany
     */
    public function webFamilies() {
        return $this->belongsToMany(WebFamily::class, 'WebFamily_WebCollection', 'webcollection_id', 'webfamily_id')->wherePivot('deleted_at', '=', '0000-00-00 00:00:00')->withPivot(['is_featured', 'display_order']);
    }

    public function webAttributes() {
        return $this->belongsToMany(WebAttribute::class, 'WebAttribute_WebCollection', 'webcollection_id', 'webattribute_id')->wherePivot('deleted_at', '=', '0000-00-00 00:00:00')->withPivot(['display_order']);
    }

    public function webCollection_Algolia()
    {
        return $this->hasMany(WebCollection_Algolia::class, 'webCollection_id', 'id');
    }

    public function visibleWebFamilies() {
        return $this->belongsToMany(WebFamily::class, 'WebFamily_WebCollection', 'webcollection_id', 'webfamily_id')
            ->wherePivot('deleted_at', '=', '0000-00-00 00:00:00')
            ->withPivot(['is_featured', 'display_order'])
            ->webVisible()
            ->displayOrder()
        ;
    }

    public function visibleInSilo($webSilo, $processDownChain = true, $processUpChain = true) {
        $isFamilyVisible = !$processDownChain;
        $isCategoryVisible = !$processUpChain;

        if (!$webSilo instanceof WebSilo) $webSilo = WebSilo::find($webSilo);

        if (count($this->webSiloOverrides)) {
            foreach ($this->webSiloOverrides as $webSiloOverride) {
                if ($webSiloOverride->websilo_id == $webSilo->id && $webSiloOverride->is_visible == 0) {
                    return false;
                }
            }
        }

        if($processDownChain){
            foreach ($this->webFamilies as $webFamily) {
                if ($webFamily->visibleInSilo($webSilo, true, false)){
                    $isFamilyVisible = true;
                    break;
                }
            }
        }

        if($processUpChain){
            foreach ($this->webCategories as $webCategory) {
                if ($webCategory->visibleInSilo($webSilo, false, true)){
                    $isCategoryVisible = true;
                    break;
                }
            }
        }

        return ($isFamilyVisible && $isCategoryVisible);
    }

    public function scopeDisplayOrder(Builder $query) {
        return $query->orderBy('pivot_display_order', 'asc')->orderBy('name', 'asc');
    }

    public function scopeAlphabetical(Builder $query) {
        return $query->orderBy('name', 'asc');
    }

    public function getFeaturedChildrenAttribute() {
        return $this->visibleWebFamilies()->wherePivot('is_featured', 1)->get();
    }

    public function getChildrenAttribute() {
        $children = $this->visibleWebFamilies();
        if (request()->get('ap', false) == 1) $children->webSiloApproved();

        return $children->get();
    }

    public function scopeInCategory($query, $webCategoryId) {
        return $query->whereHas('webCategories', function ($query) use ($webCategoryId) {
            $query->where('webcategory_id', $webCategoryId);
        });
    }

    public function scopeHavingFamily($query, $webFamilyId) {
        return $query->whereHas('webFamilies', function ($query) use ($webFamilyId) {
            $query->where('webfamily_id', $webFamilyId);
        });
    }

    public function setWebCategoryIdsAttribute($ids) {
        $this->webCategories()->sync($ids);
    }

    public function getHierarchyPathsAttribute() {
        $paths = [];
        foreach ($this->webCategories as $webCategory) {
            foreach ($webCategory->webGroups as $webGroup) {
                foreach ($webGroup->webHierarchies as $webHierarchy) {
                    $paths[] = [
                        'webHierarchy' => $webHierarchy,
                        'webGroup' => $webGroup,
                        'webCategory' => $webCategory,
                    ];
                }
            }
        }
        return $paths;
    }

    public static function deduplicatedList() {
        $webCollections = WebCollection::with('webCategories.webGroups.webHierarchies')->without('webSiloOverride')->get()->sortBy('name')->keyBy('id');

        $output = [];
        foreach ($webCollections as $id => $webCollection) {
            foreach ($webCollection->hierarchyPaths as $path) {
                $string = $webCollection->name;
                $string .= ' (' . $path['webCategory']->name;
                $string .= ' -> ' . $path['webGroup']->name;
                $string .= ' -> ' . $path['webHierarchy']->name . ')';
                $output[$id] = $string;
                break;
            }
        }
        return $output;
    }

    public function scopeInCollection($query, $webCollection) {
        return $query->whereHas('webCollections', function ($query) use ($webCollection) {
            $query->where('webcollection_id', $webCollection->id);
        });
    }

    public function scopeInGroup($query, $webGroupId) {
        return $query->whereHas('webCategories', function ($query) use ($webGroupId) {
            return $query->inGroup($webGroupId);
        });
    }

    public function scopeInSilo($query, $webSiloId) {
        return $query->whereHas('webCategories', function ($query) use ($webSiloId) {
            return $query->inSilo($webSiloId);
        });
    }    

    public function getAssetPrefix() {
        return "webCollections/{$this->id}";
    }

    public function scopeVisible(Builder $query) {
        $query
            ->where('WebCollections.is_visible', '1')
            ->whereHas('webCategories', function ($query) {
                return $query->visible();
            })
        ;

        return $query;
    }

    public function scopeHasVisibleChildren(Builder $query, $activeWebSilo = false, $activeCountry = false, $activePlant = false) {
        return $query->where(function ($where) {
            return $where
                ->whereDoesntHave('webSiloOverride')
                ->orWhereHas('webSiloOverride', function ($query) {
                    return $query->where('WebSiloOverrides.is_visible', 1);
//                        ->where('WebSiloOverrides.websilo_id', '=', b2b()->activeWebSilo()->id)
//                        ->where('WebSiloOverrides.language_code', '=', b2b()->activeLanguage());
                });
            })->whereHas('webFamilies', function ($query) use ($activeWebSilo, $activeCountry, $activePlant) {
                return $query->isVisible()->hasVisibleChildren($activeWebSilo, $activeCountry, $activePlant);
            });
    }

    public function scopeHasVisibleParents(Builder $query, $activeWebSilo = false) {
        return $query->where(function ($where) {
                return $where
                    ->whereDoesntHave('webSiloOverride')
                    ->orWhereHas('webSiloOverride', function ($query) {
                        return $query->where('WebSiloOverrides.is_visible', 1);
//                            ->where('WebSiloOverrides.websilo_id', '=', b2b()->activeWebSilo()->id)
//                            ->where('WebSiloOverrides.language_code', '=', b2b()->activeLanguage());
                    });
            })->whereHas('webCategories', function ($query) use ($activeWebSilo) {
                return $query->hasVisibleParents($activeWebSilo);
            });
    }

    public function scopeIsVisible(Builder $query) {
        return $query->where('is_visible', '1');
    }

    public function scopeWebVisible(Builder $query) {
        return $query
            ->where('is_visible', '1')
            ->where(function ($where) {
                $where
                    ->whereDoesntHave('webSiloOverride')
                    ->orWhereHas('webSiloOverride', function ($query) {
                        return $query->where('WebSiloOverrides.is_visible', '=', 1);
                    })
                ;
            })
            ->whereHas('webFamilies', function ($webFamiliesQuery) {
                return $webFamiliesQuery->webVisible();
            })
        ;
    }

    public function scopeWebSiloApproved(Builder $query) {
        return $query
            ->whereHas('webFamilies', function ($webFamiliesQuery) {
                return $webFamiliesQuery->webSiloApproved();
            })
            ;
    }

    public function slugUrl() {
        return route('collection.slug', [$this->slug,
            'g'=> session()->get('breadcrumb.groupId') ? session()->get('breadcrumb.groupId') : $this->webCategories->first()->webGroups->first()->id,
            'c' => session()->get('breadcrumb.categoryId') ? session()->get('breadcrumb.categoryId') : $this->webCategories->first()->id,
            'l' => $this->id]);
    }

    public function getParentRelationName() {
        return 'webCategories';
    }

    public function getPrimaryImage() {
        $asset = \Illuminate\Support\Arr::get($this, 'webSiloOverride.primaryImage', null);
        if (!is_null($asset)) return $asset;

        $asset = $this->assetsByType('primary')->first();
        if (!is_null($asset)) return $asset;

        $webFamily = $this->visibleWebFamilies->first();
        if ($webFamily) return $webFamily->getPrimaryImage();
    }

    public function getIsWebVisibleAttribute() {
        return static::webVisible()->where('id', $this->id)->count() > 0;
    }

    public function getMetadataDescriptionAttribute() {
        $value = $this->getMetadata('description', b2b()->activeLanguage());
        if (strlen($value)) return $value;

        return trim(preg_replace('/(\s*<.*?>\s*)+/', ' ', $this->detail));
    }

    public function getMetadataTitleAttribute() {
        $value = $this->getMetadata('title', b2b()->activeLanguage());
        if (strlen($value)) return $value;

        return $this->name;
    }

    public function scopeInHierarchy ($query, $webhierarchy_id = null) {
        if (is_null($webhierarchy_id)) {
            $webhierarchy_id = b2b()->activeWebHierarchy()->id;
        }

        return $query->whereExists(function ($query) use ($webhierarchy_id) {
            return $query
                ->select(DB::raw('1'))
                ->from('WebCollection_WebCategory')
                ->whereRaw('WebCollections.id = WebCollection_WebCategory.webcollection_id')
                ->whereRaw('WebCollection_WebCategory.deleted_at = 0')
                ->whereExists(function ($query) use ($webhierarchy_id) {
                    return $query
                        ->select(DB::raw('1'))
                        ->from('WebCategories')
                        ->whereRaw('WebCategories.id = WebCollection_WebCategory.webcategory_id')
                        ->whereRaw('WebCategories.deleted_at = 0')
                        ->whereExists(function ($query) use ($webhierarchy_id) {
                            return $query
                                ->select(DB::raw('1'))
                                ->from('WebCategory_WebGroup')
                                ->whereRaw('WebCategories.id = WebCategory_WebGroup.webcategory_id')
                                ->whereRaw('WebCategory_WebGroup.deleted_at = 0')
                                ->whereExists(function ($query) use ($webhierarchy_id) {
                                    return $query
                                        ->select(DB::raw('1'))
                                        ->from('WebGroups')
                                        ->whereRaw('WebGroups.id = WebCategory_WebGroup.webgroup_id')
                                        ->whereRaw('WebGroups.deleted_at = 0')
                                        ->whereExists(function ($query) use ($webhierarchy_id) {
                                            return $query
                                                ->select(DB::raw('1'))
                                                ->from('WebGroup_WebHierarchy')
                                                ->whereRaw('WebGroups.id = WebGroup_WebHierarchy.webgroup_id')
                                                ->whereRaw('WebGroup_WebHierarchy.deleted_at = 0')
                                                ->whereRaw("WebGroup_WebHierarchy.webhierarchy_id = $webhierarchy_id");
                                        });
                                });
                        });
                });
            });
    }

    public function webCategoriesInHierarchy ($webHierarchyId) {
        return $this->webCategories()->inHierarchy($webHierarchyId);
    }

    /**
     * @param array $webCollectionIds
     * @return array
     */
    public static function getWebHierarchyIdsForCollections (array $webCollectionIds): array {
        $webHierarchiesRaw = DB::select(
            "SELECT WebHierarchies.* 
                FROM WebCollections 
                JOIN WebCollection_WebCategory ON WebCollection_WebCategory.webcollection_id = WebCollections.id AND WebCollection_WebCategory.deleted_at = 0
                JOIN WebCategories ON WebCategories.id = WebCollection_WebCategory.webcategory_id AND WebCategories.deleted_at = 0
                JOIN WebCategory_WebGroup ON WebCategory_WebGroup.webcategory_id = WebCategories.id AND WebCategory_WebGroup.deleted_at = 0
                JOIN WebGroups ON WebGroups.id = WebCategory_WebGroup.webgroup_id AND WebGroups.deleted_at = 0
                JOIN WebGroup_WebHierarchy ON WebGroup_WebHierarchy.webgroup_id = WebGroups.id AND WebGroup_WebHierarchy.deleted_at = 0
                JOIN WebHierarchies ON WebHierarchies.id = WebGroup_WebHierarchy.webhierarchy_id AND WebHierarchies.deleted_at = 0
                WHERE WebCollections.id IN (?)",
            [implode(',', $webCollectionIds)]
        );

        $webHierarchyIds = WebHierarchy::hydrate($webHierarchiesRaw)->pluck('id')->toArray();
        return array_unique($webHierarchyIds);
    }

    use HasAssets, HasSlug, HasLandingPage, HasWebSiloOverrides, HasModelTranslations, HasMetadata;
}