<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Carbon\Carbon;

class Todo extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'title',
        'description',
        'todo_time',
        'reminder_before',
        'reminder_sent',
        'reminder_sent_at',
        'status',
        'priority',
        'is_completed',
        'completed_at',
        'is_recurring',
        'recurrence_type',
        'recurrence_interval',
        'recurrence_days',
        'recurrence_end_date',
        'parent_todo_id',
        'attachments',
        'shared_with',
        'share_permission',
        'category',
        'tags',
        'reminder_times',
        'reminders_sent',
        'snoozed_until',
        'snooze_count',
        'location',
        'metadata',
    ];

    protected $casts = [
        'todo_time' => 'datetime',
        'reminder_sent_at' => 'datetime',
        'completed_at' => 'datetime',
        'reminder_sent' => 'boolean',
        'is_completed' => 'boolean',
        'is_recurring' => 'boolean',
        'recurrence_end_date' => 'datetime',
        'recurrence_days' => 'array',
        'attachments' => 'array',
        'shared_with' => 'array',
        'tags' => 'array',
        'reminder_times' => 'array',
        'reminders_sent' => 'array',
        'snoozed_until' => 'datetime',
        'metadata' => 'array',
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Calculate when the reminder should be sent
     */
    public function getReminderTimeAttribute()
    {
        return Carbon::parse($this->todo_time)->subMinutes($this->reminder_before);
    }

    /**
     * Check if reminder should be sent now
     */
    public function shouldSendReminder()
    {
        if ($this->reminder_sent || $this->is_completed || $this->status !== 'pending') {
            return false;
        }

        $reminderTime = $this->reminder_time;
        $now = Carbon::now();

        // Send reminder if current time is past reminder time and before todo time
        return $now->greaterThanOrEqualTo($reminderTime) && $now->lessThan($this->todo_time);
    }

    /**
     * Mark reminder as sent
     */
    public function markReminderSent()
    {
        $this->update([
            'reminder_sent' => true,
            'reminder_sent_at' => now(),
        ]);
    }

    /**
     * Mark todo as completed
     */
    public function markAsCompleted()
    {
        $this->update([
            'is_completed' => true,
            'status' => 'completed',
            'completed_at' => now(),
        ]);
    }

    /**
     * Get time until todo
     */
    public function getTimeUntilTodoAttribute()
    {
        return Carbon::now()->diffInMinutes($this->todo_time, false);
    }

    /**
     * Get formatted reminder time label
     */
    public function getReminderLabelAttribute()
    {
        $minutes = $this->reminder_before;
        
        if ($minutes == 60) return '1 hour before';
        if ($minutes == 120) return '2 hours before';
        if ($minutes == 300) return '5 hours before';
        
        return $minutes . ' minutes before';
    }

    /**
     * Scope for pending todos
     */
    public function scopePending($query)
    {
        return $query->where('status', 'pending')->where('is_completed', false);
    }

    /**
     * Scope for completed todos
     */
    public function scopeCompleted($query)
    {
        return $query->where('is_completed', true);
    }

    /**
     * Scope for overdue todos
     */
    public function scopeOverdue($query)
    {
        return $query->where('status', 'pending')
            ->where('is_completed', false)
            ->where('todo_time', '<', now());
    }

    /**
     * Scope for upcoming todos
     */
    public function scopeUpcoming($query, $hours = 24)
    {
        return $query->where('status', 'pending')
            ->where('is_completed', false)
            ->where('todo_time', '>', now())
            ->where('todo_time', '<=', now()->addHours($hours));
    }

    /**
     * Scope for todos needing reminder
     */
    public function scopeNeedsReminder($query)
    {
        return $query->where('status', 'pending')
            ->where('is_completed', false)
            ->where('reminder_sent', false)
            ->where(function ($q) {
                $q->whereNull('snoozed_until')
                  ->orWhere('snoozed_until', '<=', now());
            })
            ->whereRaw('DATE_SUB(todo_time, INTERVAL reminder_before MINUTE) <= NOW()')
            ->where('todo_time', '>', now());
    }

    /**
     * Snooze todo reminder
     */
    public function snooze($minutes)
    {
        $this->update([
            'snoozed_until' => now()->addMinutes($minutes),
            'snooze_count' => $this->snooze_count + 1,
        ]);
    }

    /**
     * Check if todo is snoozed
     */
    public function isSnoozed()
    {
        return $this->snoozed_until && $this->snoozed_until->isFuture();
    }

    /**
     * Create next recurring instance
     */
    public function createNextRecurrence()
    {
        if (!$this->is_recurring || !$this->recurrence_type) {
            return null;
        }

        $nextTime = $this->calculateNextRecurrenceDate();

        if (!$nextTime || ($this->recurrence_end_date && $nextTime->greaterThan($this->recurrence_end_date))) {
            return null;
        }

        return self::create([
            'user_id' => $this->user_id,
            'title' => $this->title,
            'description' => $this->description,
            'todo_time' => $nextTime,
            'reminder_before' => $this->reminder_before,
            'status' => 'pending',
            'priority' => $this->priority,
            'is_recurring' => true,
            'recurrence_type' => $this->recurrence_type,
            'recurrence_interval' => $this->recurrence_interval,
            'recurrence_days' => $this->recurrence_days,
            'recurrence_end_date' => $this->recurrence_end_date,
            'parent_todo_id' => $this->parent_todo_id ?? $this->id,
            'category' => $this->category,
            'tags' => $this->tags,
            'location' => $this->location,
        ]);
    }

    /**
     * Calculate next recurrence date
     */
    protected function calculateNextRecurrenceDate()
    {
        $current = Carbon::parse($this->todo_time);

        switch ($this->recurrence_type) {
            case 'daily':
                return $current->addDays($this->recurrence_interval);
            
            case 'weekly':
                if ($this->recurrence_days && is_array($this->recurrence_days)) {
                    // Find next day of week in recurrence_days array
                    $currentDay = $current->dayOfWeek;
                    sort($this->recurrence_days);
                    
                    foreach ($this->recurrence_days as $day) {
                        if ($day > $currentDay) {
                            return $current->next($day);
                        }
                    }
                    // If no future day this week, go to first day next week
                    return $current->addWeek()->next($this->recurrence_days[0]);
                }
                return $current->addWeeks($this->recurrence_interval);
            
            case 'monthly':
                return $current->addMonths($this->recurrence_interval);
            
            case 'yearly':
                return $current->addYears($this->recurrence_interval);
            
            default:
                return null;
        }
    }

    /**
     * Check if todo is shared with user
     */
    public function isSharedWith($userId)
    {
        return is_array($this->shared_with) && in_array($userId, $this->shared_with);
    }

    /**
     * Share todo with user
     */
    public function shareWith($userId, $permission = 'view')
    {
        $sharedWith = $this->shared_with ?? [];
        
        if (!in_array($userId, $sharedWith)) {
            $sharedWith[] = $userId;
            $this->update([
                'shared_with' => $sharedWith,
                'share_permission' => $permission,
            ]);
        }
    }

    /**
     * Unshare todo from user
     */
    public function unshareWith($userId)
    {
        $sharedWith = $this->shared_with ?? [];
        
        if (($key = array_search($userId, $sharedWith)) !== false) {
            unset($sharedWith[$key]);
            $this->update(['shared_with' => array_values($sharedWith)]);
        }
    }

    /**
     * Add attachment
     */
    public function addAttachment($filePath)
    {
        $attachments = $this->attachments ?? [];
        $attachments[] = $filePath;
        $this->update(['attachments' => $attachments]);
    }

    /**
     * Remove attachment
     */
    public function removeAttachment($filePath)
    {
        $attachments = $this->attachments ?? [];
        
        if (($key = array_search($filePath, $attachments)) !== false) {
            unset($attachments[$key]);
            $this->update(['attachments' => array_values($attachments)]);
        }
    }

    /**
     * Scope for recurring todos
     */
    public function scopeRecurring($query)
    {
        return $query->where('is_recurring', true);
    }

    /**
     * Scope for todos by category
     */
    public function scopeByCategory($query, $category)
    {
        return $query->where('category', $category);
    }

    /**
     * Scope for todos with tag
     */
    public function scopeWithTag($query, $tag)
    {
        return $query->whereJsonContains('tags', $tag);
    }

    /**
     * Scope for shared todos
     */
    public function scopeSharedWithUser($query, $userId)
    {
        return $query->whereJsonContains('shared_with', $userId);
    }
}
