<?php

namespace App\Traits;

use App\Models\Account;
use App\Models\Tag;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Spatie\Activitylog\Models\Activity;

trait ProfileTrait
{
    /***
     * Retrieve the online status of the user and sets the properties isOnline and isAway accordingly.
     *
     * @return void
     */
    public function getOnlineStatus()
    {

        // TODO: Replace commented rtippin messenger logic with wirechat logic
        // Check online status of the user
        // $messenger = app(Messenger::class);
        // $status = $messenger->getProviderOnlineStatus($this->profile);

        // if ($status === 1) {
        //     $this->isOnline = true;
        //     $this->isAway = false;
        // } elseif ($status === 2) {
        //     $this->isOnline = false;
        //     $this->isAway = true;
        // } else {
        //     $this->isOnline = false;
        //     $this->isAway = false;
        // }
    }


    /**
     * Retrieve the phone number of the profile.
     *
     * @return void
     */
    public function getPhone($profile)
    {
        if ($profile->phone_public) {
            return $profile->phone;
        } else {
            return null;
        }
    }


    /**
     * Get the profile's location and generate a link to OpenStreetMap.
     *
     * @return void
     */
    public function getLocation($profile)
    {
        return$profile->getLocationFirst(true);
    }


    /**
     * Retrieve the user's languages and their language competence.
     *
     * @return void
     */
    public function getLanguages($profile)
    {
        // If languages is null, return an empty collection
        if (empty($profile->languages)) {
            return collect();
        }

        return $profile->languages->map(function ($language) {
            $language->competence_name = DB::table('language_competences')->find($language->pivot->competence)->name;
            return $language;
        });
    }


    public function getLangPreference($profile)
    {
        // Get the user's language preference (if it exists)
        $lang_preference = DB::table('languages')->where('lang_code',$profile->lang_preference)->first();
        if ($lang_preference) {
            return $lang_preference->name;
        }
    }


    /**
     * Retrieves the skills of this user.
     *
     * @return \Illuminate\Support\Collection
     */
    //TODO! This will set the skill Cache, and not get the skills from cache! FIX THIS!
    public function getSkills($profile)
    {
        $skillsCache = Cache::remember('skills-user-' .$profile->id . '-lang-' . app()->getLocale(), now()->addDays(7), function () use ($profile) { // remember cache
            $tagIds = $profile->tags->pluck('tag_id');
            $translatedTags = collect((new Tag())->translateTagIdsWithContexts($tagIds, App::getLocale(), App::getFallbackLocale()));     // Translate to app locale, if not available to fallback locale, if not available do not translate

            $skills = $translatedTags->map(function ($item) {
                return [
                    'tag_id' => $item['tag_id'],
                    'name' => $item['tag'],
                    'foreign' => (isset($item['locale']['locale']) && $item['locale']['locale'] == App::getLocale()) ? false : true,
                    'example' => (isset($item['locale']) && isset($item['locale']['example'])) ? $item['locale']['example'] : null,
                    'category' => $item['category'],
                    'category_path' =>  $item['category_path'],
                    'category_color' =>  $item['category_color'],
                    'title' =>  $item['category_path']
                ];
            });

            $skills = collect($skills);

            return $skills;
        });

        $skills = $skillsCache;

        if ($skills) {
            return $skills;
        } else {
            return null;
        }
    }

    
    public function getAge($profile)
    {
        // Check if the table has the date_of_birth column
        if (Schema::hasColumn($profile->getTable(), 'date_of_birth') && $profile->date_of_birth) {
            return Carbon::parse($profile->date_of_birth)->age;
        }

        return null;
    }

    
    /**
     * Get the last login time for the profile.
     *
     * @return void
     */
    public function getLastLogin($profile)
    {
        $activityLog =
            Activity::where('subject_id', $profile->id)
            ->where('subject_type', get_class($profile))
            ->whereNotNull('properties->old->last_login_at')
            ->get('properties')->last();
        if (isset($activityLog)) {
            $lastLoginAt = json_decode($activityLog, true)['properties']['old']['last_login_at'];
            return  Carbon::createFromTimeStamp(strtotime($lastLoginAt))->diffForHumans();
        } elseif ($profile->last_login_at)  {
            $lastLoginAt = $profile->last_login_at;
            return  Carbon::createFromTimeStamp(strtotime($lastLoginAt))->diffForHumans();
        } else {
            return null;
        }
    }



    /**
     * Retrieves the totals of the user's accounts.
     * This method calls the `getAccountsTotals` method of the `Account` model to calculate the totals of the user's accounts.
     *
     */
    public function getAccountsTotals($profile)
    {
        $type = strtolower(class_basename($profile));
        $totals = (new Account())->getAccountsTotals(get_class($profile), $profile->id, timebank_config('account_info.'.$type.'.countTransfersSince'));

        if ($totals) {
            return $totals;
        } else {
            return null;
        }
    }


    /**
     * Get the last exchange date for the profile.
     *
     * @return void
     */
    public function getLastExchangeAt($accountsTotals = null, $profile = null)
    {
        if (!$accountsTotals && $profile) {
            $accountsTotals = (new Account())->getAccountsTotals($profile->id, timebank_config('account_info.account_totals.countTransfersSince'));
        }

        // Normalize lastTransferDate to always be an array
        if (!isset($accountsTotals['lastTransferDate'])) {
            $accountsTotals['lastTransferDate'] = [];
        } elseif (!is_array($accountsTotals['lastTransferDate'])) {
            $accountsTotals['lastTransferDate'] = [$accountsTotals['lastTransferDate']];
        }

        if (!empty($accountsTotals['lastTransferDate'][0])) {
            $date = $accountsTotals['lastTransferDate'][0];
            if ($date instanceof \Illuminate\Support\Carbon) {
                return $date->diffForHumans();
            } else {
                return Carbon::parse($date)->diffForHumans();
            }
        } else {
            return null;   // no transfers
        }
    }



    /**
     * Calculates and sets the registered since date for the user.
     *
     * @return void
     */
    public function getRegisteredSince($profile)
    {
        $createdAt = Carbon::parse($profile->created_at);
        $registeredSince = $createdAt->diffForHumans();

        if ($registeredSince) {
            return $registeredSince;
        } else {
            return null;
        }
    }


    /**
     * Retrieves the social media accounts associated with this user.
     *
     * @return void
     */
    public function getSocials($profile)
    {
        $socials = $profile->socials()
            ->withPivot(['user_on_social', 'server_of_social', 'created_at', 'updated_at'])
            ->orderByPivot('updated_at', 'desc')
            ->limit(10)
            ->get();

        return $socials->isNotEmpty() ? $socials : collect();
    }


    /**
     * Check if a model has an incomplete profile based on configured fields and relations.
     *
     * @param \Illuminate\Database\Eloquent\Model $model
     * @return bool
     */
    public function hasIncompleteProfile($model)
    {
        $config = timebank_config('profile_incomplete');
        
        if (!$config) {
            return false;
        }

        $checkFields = $config['check_fields'] ?? [];
        $checkRelations = $config['check_relations'] ?? [];
        $minTotalLength = $config['check_fields_min_total_length'] ?? 0;

        // Check if at least one field has data and calculate total length
        $hasFieldData = false;
        $totalFieldLength = 0;
        foreach ($checkFields as $field) {
            if (!empty($model->{$field})) {
                $hasFieldData = true;
                $totalFieldLength += strlen(trim($model->{$field}));
            }
        }

        // Check if minimum total length requirement is met
        $meetsMinLength = $totalFieldLength >= $minTotalLength;

        // Check if at least one relation has data
        $hasRelationData = false;
        foreach ($checkRelations as $relation) {
            if (!$model->relationLoaded($relation)) {
                $model->load($relation);
            }
            
            if (!$model->{$relation}->isEmpty()) {
                $hasRelationData = true;
                break;
            }
        }

        // Profile is complete (return false) when ALL three conditions are met:
        // 1. At least one field has data
        // 2. Total length meets minimum requirement
        // 3. At least one relation has data
        $isComplete = $hasFieldData && $meetsMinLength && $hasRelationData;
        
        // Return true if incomplete, false if complete
        return !$isComplete;
    }

    /**
     * Returns true if the profile has never received a transaction on any of its active accounts.
     */
    public function hasNeverReceivedTransaction($model): bool
    {
        if (!method_exists($model, 'accounts')) {
            return false;
        }

        $accountIds = $model->accounts()->pluck('id');

        if ($accountIds->isEmpty()) {
            return true;
        }

        return !\App\Models\Transaction::whereIn('to_account_id', $accountIds)->exists();
    }

}
