<?php

namespace Hilco\Models;

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

/**
 * Class WebCategory
 * @package Hilco\Models
 * @method static WebCategory firstOrNew(array $attributes)
 */
class WebCategory extends WebModel implements HasLandingPageInterface, HasWebSiloOverridesInterface {
    protected $table = "WebCategories";
    protected $fillable = ['name', 'slug', 'webGroupIds', 'is_visible', 'detail', 'sort_priority', 'metadata_title', 'metadata_description', 'commit_sequence'];
    protected $casts = [
        ['is_visible' => 'boolean']
    ];
    protected $with = ['webSiloOverride'];
    protected $perPage = 24;
    protected $hierarchyParent = WebGroup::class;

//    use KeyWordsFunctional;

    public static function maxCommit(): int {
        return WebCategory::withTrashed()->max("commit_sequence");
    }

    public static function nextCommit(): int {
        return WebCategory::maxCommit() + 1;
    }

    public static function createWebCategory (array $webcategoryData, array $webgroups, array $webcollections) {
        if (! isset($webcategoryData['commit_sequence'])) {
            $webcategoryData['commit_sequence'] = WebCategory::nextCommit();
        }
        $newWebCategory = new WebCategory($webcategoryData);
        $newWebCategory->save();
        $newWebCategory->refresh();
        if (count($webgroups)) {
            $wcwgCS = WebCategory_WebGroup::withTrashed()->max('commit_sequence') + 1;
            $wgQuery = WebGroup::whereIn('id', $webgroups)
                ->selectRaw("$newWebCategory->id AS webcategory_id, WebGroups.id AS webgroup_id, $wcwgCS AS commit_sequence");
            WebCategory_WebGroup::insertUsing([
                'webcategory_id', 'webgroup_id', 'commit_sequence'
            ], $wgQuery);
        }
        if (count($webcollections)) {
            $wcwcCS = WebCollection_WebCategory::withTrashed()->max('commit_sequence') + 1;
            $wgQuery = WebCollection::whereIn('id', $webcollections)
                ->selectRaw("WebCollections.id AS webcollection_id, $newWebCategory->id AS webcategory_id, $wcwcCS AS commit_sequence");
            WebCollection_WebCategory::insertUsing([
                'webcollection_id', 'webcategory_id', 'commit_sequence'
            ], $wgQuery);
        }
        return $newWebCategory;
    }

    public static function deleteWebCategory ($id) {
        $webCategory = WebCategory::find($id);
        $wcwgIds = $webCategory->webCategoryWebGroups->pluck('id')->toArray();
        $wcwcIds = $webCategory->webCollectionWebCategories->pluck('id')->toArray();

        $webCategory->delete();
        WebCategory::onlyTrashed()->find($id)->update(['commit_sequence' => WebCategory::nextCommit()]);

        if (count($wcwgIds)) {
            WebCategory_WebGroup::findMany($wcwgIds)->delete();
            WebCategory_WebGroup::onlyTrashed()->findMany($wcwgIds)->update([
                'commit_sequence' => WebCategory_WebGroup::nextCommit()
            ]);
        }

        if (count($wcwcIds)) {
            WebCollection_WebCategory::findMany($wcwcIds)->delete();
            WebCollection_WebCategory::onlyTrashed()->findMany($wcwcIds)->update([
                'commit_sequence' => WebCollection_WebCategory::nextCommit()
            ]);
        }
    }

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

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function webGroups() {
        return $this->belongsToMany(WebGroup::class, 'WebCategory_WebGroup', 'webcategory_id', 'webgroup_id')
            ->wherePivot('deleted_at', '=', '0000-00-00 00:00:00')
            ->withPivot('display_order');
    }

    public function webCategoryWebGroups() {
        return $this->hasMany(WebCategory_WebGroup::class, "webcategory_id", "id");
    }

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

    public function webCollectionWebCategories() {
        return $this->hasMany(WebCollection_WebCategory::class, "webcategory_id", "id");
    }

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

    public function visibleWebCollections() {
        return $this->belongsToMany(WebCollection::class, 'WebCollection_WebCategory', 'webcategory_id', 'webcollection_id')
            ->wherePivot('deleted_at', '=', '0000-00-00 00:00:00')
            ->withPivot('display_order')
            ->webVisible()
            ->displayOrder()
        ;
    }

    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 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 getFeaturedChildrenAttribute() {
        return $this->visibleWebCollections()->wherePivot('is_featured', 1)->get();
    }

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

        return $children->get();
    }

    public function scopeInGroup($query, $groupId) {
        return $query->whereHas('webGroups', function ($query) use ($groupId) {
            $query->where('webgroup_id', $groupId);
        });
    }

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

    /**
     * @deprecated this is technically only "ok" to do on create, otherwise it won't respect soft-deletes
     */
    public function setWebGroupIdsAttribute($ids) {
        $this->webGroups()->sync($ids);
    }

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

    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->whereRaw('WebSiloOverrides.is_visible = 1');
//                        ->where('WebSiloOverrides.websilo_id', '=', b2b()->activeWebSilo()->id)
//                        ->where('WebSiloOverrides.language_code', '=', b2b()->activeLanguage());
                });
            })->whereHas('webCollections', 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->whereRaw('WebSiloOverrides.is_visible = 1');
//                        ->where('WebSiloOverrides.websilo_id', '=', b2b()->activeWebSilo()->id)
//                        ->where('WebSiloOverrides.language_code', '=', b2b()->activeLanguage());
                });
            })->whereHas('webGroups', function ($query) use ($activeWebSilo) {
                return $query->hasVisibleParents($activeWebSilo);
            });
    }

    public function scopeIsVisible(Builder $query) {
        return $query
            ->whereRaw('is_visible =1')
            ->where(function ($where) {
                $where
                    ->whereDoesntHave('webSiloOverride')
                    ->orWhereHas('webSiloOverride', function ($query) {
                        return $query->whereRaw('WebSiloOverrides.is_visible = 1');
                    })
                ;
            })
        ;
    }

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

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

    public function scopeVisible(Builder $query) {
        return $query
            ->whereRaw('WebCategories.is_visible =1')
            ->whereHas('webGroups', function ($query) {
                return $query->visible();
            })
        ;
    }

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

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

    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;

        $webCollection = $this->visibleWebCollections->first();
        if ($webCollection) return $webCollection->getPrimaryImage();
    }

    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;
    }

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

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

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

    public function visibleInSilo($webSilo, $processDownChain = true, $processUpChain = true) {
        $isCollectionVisible = !$processDownChain;
        $isGroupVisible = !$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->webCollections as $webCollection) {
                if ($webCollection->visibleInSilo($webSilo, true, false)){
                    $isCollectionVisible = true;
                    break;
                }
            }
        }

        if($processUpChain){
            foreach ($this->webGroups as $webGroup) {
                if ($webGroup->visibleInSilo($webSilo, false, true)){
                    $isGroupVisible = true;
                    break;
                }
            }
        }

        return ($isCollectionVisible && $isGroupVisible);
    }

    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('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 webGroupsInHierarchy ($webHierarchyId) {
        return $this->webGroups()->inHierarchy($webHierarchyId);
    }
}