<?php

namespace App\Models\Companies;

use App\Models\Advisories\AdvisoryCompany;
use App\Models\Asset;
use App\Models\User;
use App\Services\DaDataService;
use App\Support\RelationValuesTrait;
use App\Support\UuidScopeTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

class Company extends Model {
    use UuidScopeTrait, SoftDeletes, RelationValuesTrait;

    protected $dates = [
        'tax_registration_date',
        'deleted_at'
    ];

    protected $fillable = [
        'uuid',
        'logo_id',
        'name',
        'full_name',
        'inn',
        'kpp',
        'ogrn',
        'okpo',
        'okved',
        'okato',
        'tax_registration_date',
        'is_main'
    ];

    protected $hidden = [
        'id',
        'deleted_at',
        'updated_at',
        'pivot'
    ];

    public function logo(): BelongsTo {
        return $this->belongsTo(Asset::class);
    }

    public function types(): HasMany {
        return $this->hasMany(CompanyType::class);
    }

    public function departments(): HasMany {
        return $this->hasMany(Department::class);
    }

    public function members(): HasMany {
        return $this->hasMany(CompanyMember::class);
    }
    public function rootMembers(): HasMany {
        return $this->members()->whereNull('department_id');
    }
    public function management(): HasMany {
        return $this->members()->whereIn('status', [CompanyMemberRank::VICE, CompanyMemberRank::CHIEF]);
    }
    public function vices(): HasMany {
        return $this->members()->where(['status' => CompanyMemberRank::VICE]);
    }
    public function employees(): HasMany {
        return $this->members()->where(['status' => CompanyMemberRank::EMPLOYEE]);
    }

    public function addresses(): HasMany {
        return $this->hasMany(Address::class);
    }

    public function bankDetails(): HasOne {
        return $this->hasOne(BankDetails::class);
    }

    public function contacts(): HasMany {
        return $this->hasMany(Contact::class);
    }
    public function phones(): HasMany {
        return $this->contacts()->where(['type' => ContactType::PHONE]);
    }
    public function emails(): HasMany {
        return $this->contacts()->where(['type' => ContactType::EMAIL]);
    }

    public function advisoryCompanies(): HasMany {
        return $this->hasMany(AdvisoryCompany::class);
    }



    public function scopeByTypes($query, $types) {
        return $query->whereHas('types', function($query) use($types) {
            $query->whereIn('name', is_array($types) ? $types : [$types]);
        });
    }


    public function getLegalAddressAttribute(): Model {
        return $this->addresses()->firstOrCreate(['type' => Address::$TYPE_LEGAL]);
    }
    public function getActualAddressAttribute(): Model {
        return $this->addresses()->firstOrCreate(['type' => Address::$TYPE_ACTUAL]);
    }
    public function getPhoneAttribute(): Model {
        return $this->phones()->firstOrCreate(['type' => ContactType::PHONE]);
    }
    public function getEmailAttribute(): Model {
        return $this->emails()->firstOrCreate(['type' => ContactType::EMAIL]);
    }
    public function getRootDepartmentAttribute(): Model {
        $res = $this->departments()->whereNull('parent_id')->firstOrCreate(['name' => 'root']);
        if (!$res->title) $res->update(['title' => 'Дирекция']);
        return $res;
    }
    public function getRepresentativeMemberAttribute() {
        return $this->members()->where(['representative' => true])->first();
    }
    public function getResponsibleMemberAttribute() {
        return $this->members()->orderBy('representative', 'desc')->first();
    }


    public static function getByData($data) {
        $result = false;
        if (!empty($data['inn'])) {
            $result = self::firstOrCreate(['inn' => $data['inn']]);
            (new DaDataService($data['inn']))->saveToCompany($result);
            if ($val = $data['name'] ?? null) $result->update(['name' => $val, 'full_name' => $val]);
            if (($val = $data['address'] ?? null) && $result->legalAddress->full !== $val) $result->setAddress($val);
            if ($val = $data['phone'] ?? null) $result->setPhone($val);
            if ($val = $data['email'] ?? null) $result->setEmail($val);
            if ($val = $data['contacts'] ?? null) $result->setContacts($val);
            if ($val = $data['types'] ?? null) $result->setTypes($val);
            if ($val = $data['logo'] ?? null) $result->setLogo($val);
            if (!$result->name && !is_numeric($result->inn)) $result->update(['name' => $result->inn, 'full_name' => $result->inn]);
        }
        return $result;
    }

    public function addMember(User $user, $position, $departmentId = null, $rank = null): Model {
        if ($member = $this->members()->where(['user_id' => $user->id, 'position' => $position])->first()) {
            if ($departmentId) $member->update(['department_id' => $departmentId]);
            if (!is_null($rank)) $member->update(['rank' => $rank]);
        } elseif ($member = $this->members()->create(['user_id' => $user->id, 'position' => $position])) {
            $member->update(['department_id' => $departmentId ?? $this->rootDepartment->id ?? null, 'rank' => $rank ?? CompanyMemberRank::EMPLOYEE]);
        }
        return $member;
    }

    public function isMember(CompanyMember $member): bool {
        return $this->members()->where('id', $member->id)->exists();
    }


    public function findDepartments($search): Collection {
        return $this->departments()->where('title', 'like', "%{$search}%")->get();
    }
    public function findMembers($search): Collection {
        return $this->members()->where('position', 'like', "%{$search}%")->orWhereHas('user', function($query) use($search) {
            $query->where('name', 'like', "%{$search}%");
        })->get();
    }


    public function setTypes(array $types) {
        $exists = collect($types)->map(function($item) {
            $name = (is_string($item)) ? $item : $item['id'] ?? null;
            return $name ? $this->types()->firstOrCreate(['name' => $name]) : null;
        });
        $this->types()->whereNotIn('name', $exists->pluck('name')->all())->delete();
    }

    public function setLogo($val) {
        $asset = Asset::byUuid($val)->first();
        $this->update(['logo_id' => $asset->id ?? null]);
    }

    public function setAddress($val) {
        $this->legalAddress->setFullAddress($val);
        $this->actualAddress->setFullAddress($val);
    }
    public function setEmail($val): ?Model {
        $this->emails()->delete();
        return $val ? $this->contacts()->create(['type' => ContactType::EMAIL, 'value' => $val]) : null;
    }
    public function setPhone($val): ?Model {
        $this->phones()->delete();
        return $val ? $this->contacts()->create(['type' => ContactType::PHONE, 'value' => $val]) : null;
    }
    public function setContacts($val) {
        $this->contacts()->firstOrCreate(['type' => ContactType::MIXED, 'value' => $val]);
        collect(explode(';', $val))->each(function($contact) {
            $type = (Str::contains($contact, '@')) ? ContactType::EMAIL : ContactType::PHONE;
            $this->contacts()->firstOrCreate(['type' => $type, 'value' => trim($contact)]);
        });
    }


    public function getPermissions(User $user): array {
        $result = ['view' => false, 'edit' => false];
        if ($user->isAdmin) $result = ['view' => true, 'edit' => true];
        elseif ($user->isCompanyMember($this)) {
            $result['view'] = true;
            if ($this->members()->where(['user_id' => $user->id, 'representative' => 1])->exists()) $result['edit'] = true;
        }
        return $result;
    }


}
