<?php

namespace App\Services;

use App\Models\Account;
use App\Models\AiLog;
use App\Models\AppNotification;
use App\Models\Category;
use App\Models\FollowUp;
use App\Models\Transaction;
use App\Models\UsageLog;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class SmartEntrySaver
{
    public function save(
        User $user,
        string $inputText,
        array $parsed,
        ?int $accountId = null,
        bool $createFollowUp = true,
    ): array {
        return DB::transaction(function () use ($user, $inputText, $parsed, $accountId, $createFollowUp): array {
            $account = $this->resolveAccount($user->id, $accountId);
            [$category, $subcategory] = $this->resolveCategories(
                $user->id,
                (string) ($parsed['type'] ?? $parsed['intent'] ?? 'expense'),
                $parsed['category'] ?? null,
                $parsed['subcategory'] ?? null,
            );

            $followUp = null;

            if ($createFollowUp && $this->shouldCreateFollowUp($parsed)) {
                $followUp = FollowUp::query()->create([
                    'user_id' => $user->id,
                    'name' => $parsed['counterparty_name'] ?? $category?->name ?? 'Reminder',
                    'mobile' => $parsed['counterparty_mobile'] ?? null,
                    'amount' => $parsed['amount'] ?? null,
                    'followup_date' => $parsed['due_at'] ?? now()->addDay(),
                    'status' => 'pending',
                    'type' => in_array($parsed['type'] ?? $parsed['intent'] ?? '', ['payable', 'receivable'], true) ? 'payment' : 'call',
                    'priority' => $this->resolvePriority($parsed['due_at'] ?? null),
                    'note' => $inputText,
                ]);

                AppNotification::query()->create([
                    'user_id' => $user->id,
                    'message' => $this->buildReminderMessage($parsed),
                    'type' => 'reminder',
                    'status' => 'pending',
                    'scheduled_at' => $parsed['due_at'] ?? null,
                ]);

                UsageLog::query()->create([
                    'user_id' => $user->id,
                    'subscription_id' => $user->currentSubscription?->id,
                    'feature' => 'reminder',
                    'count' => 1,
                    'usage_date' => now()->toDateString(),
                    'meta' => [
                        'source' => 'smart_entry',
                        'scheduled_at' => $parsed['due_at'] ?? null,
                    ],
                ]);
            }

            $transaction = Transaction::query()->create([
                'user_id' => $user->id,
                'account_id' => $account?->id,
                'category_id' => $category?->id,
                'type' => $parsed['type'] ?? $parsed['intent'] ?? 'expense',
                'amount' => $parsed['amount'] ?? 0,
                'category' => $category?->name ?? ($parsed['category'] ?? Str::title((string) ($parsed['type'] ?? 'expense'))),
                'subcategory' => $subcategory?->name ?? ($parsed['subcategory'] ?? null),
                'note' => $parsed['note'] ?? null,
                'counterparty_name' => $parsed['counterparty_name'] ?? null,
                'counterparty_mobile' => $parsed['counterparty_mobile'] ?? null,
                'purpose' => $parsed['purpose'] ?? null,
                'date' => $parsed['date'] ?? now()->toDateString(),
                'due_at' => $parsed['due_at'] ?? null,
                'direction' => $parsed['direction'] ?? 'out',
                'status' => $parsed['status'] ?? 'posted',
                'source' => $parsed['source'] ?? 'ai_text',
                'input_text' => $inputText,
                'linked_followup_id' => $followUp?->id,
            ]);

            $aiLog = AiLog::query()->create([
                'user_id' => $user->id,
                'input_text' => $inputText,
                'parsed_output' => $parsed,
                'status' => 'saved',
            ]);

            UsageLog::query()->create([
                'user_id' => $user->id,
                'subscription_id' => $user->currentSubscription?->id,
                'feature' => 'smart_entry',
                'count' => 1,
                'usage_date' => now()->toDateString(),
                'meta' => [
                    'source' => $parsed['source'] ?? 'ai_text',
                    'type' => $parsed['type'] ?? $parsed['intent'] ?? 'expense',
                ],
            ]);

            if (in_array($parsed['source'] ?? 'ai_text', ['ai_text', 'voice'], true)) {
                UsageLog::query()->create([
                    'user_id' => $user->id,
                    'subscription_id' => $user->currentSubscription?->id,
                    'feature' => 'ai_parse',
                    'count' => 1,
                    'usage_date' => now()->toDateString(),
                    'meta' => [
                        'source' => $parsed['source'] ?? 'ai_text',
                    ],
                ]);
            }

            return [
                'transaction' => $transaction->load(['account', 'categoryModel', 'followUp']),
                'follow_up' => $followUp,
                'ai_log' => $aiLog,
            ];
        });
    }

    protected function resolveAccount(int $userId, ?int $accountId): ?Account
    {
        if ($accountId) {
            return Account::query()
                ->where('user_id', $userId)
                ->find($accountId);
        }

        return Account::query()
            ->where('user_id', $userId)
            ->orderByRaw("CASE WHEN type = 'cash' THEN 0 WHEN type = 'bank' THEN 1 ELSE 2 END")
            ->orderBy('id')
            ->first();
    }

    protected function resolveCategories(int $userId, string $kind, mixed $categoryName, mixed $subcategoryName): array
    {
        $kind = in_array($kind, ['expense', 'income', 'payable', 'receivable'], true) ? $kind : 'expense';
        $category = null;
        $subcategory = null;

        if (filled($categoryName)) {
            $category = Category::query()
                ->where('kind', $kind)
                ->whereNull('parent_id')
                ->where(function ($query) use ($userId): void {
                    $query->where('user_id', $userId)
                        ->orWhere(function ($subQuery): void {
                            $subQuery->whereNull('user_id')->where('is_system', true);
                        });
                })
                ->whereRaw('LOWER(name) = ?', [Str::lower((string) $categoryName)])
                ->first();

            if (! $category) {
                $category = Category::query()->create([
                    'user_id' => $userId,
                    'name' => Str::title((string) $categoryName),
                    'slug' => Str::slug((string) $categoryName),
                    'kind' => $kind,
                    'is_system' => false,
                    'is_active' => true,
                ]);
            }
        }

        if ($category && filled($subcategoryName)) {
            $subcategory = Category::query()
                ->where('kind', $kind)
                ->where('parent_id', $category->id)
                ->where('user_id', $userId)
                ->whereRaw('LOWER(name) = ?', [Str::lower((string) $subcategoryName)])
                ->first();

            if (! $subcategory) {
                $subcategory = Category::query()->create([
                    'user_id' => $userId,
                    'parent_id' => $category->id,
                    'name' => Str::title((string) $subcategoryName),
                    'slug' => Str::slug((string) $subcategoryName),
                    'kind' => $kind,
                    'is_system' => false,
                    'is_active' => true,
                ]);
            }
        }

        return [$category, $subcategory];
    }

    protected function shouldCreateFollowUp(array $parsed): bool
    {
        return filled($parsed['due_at'] ?? null)
            || in_array($parsed['type'] ?? $parsed['intent'] ?? '', ['payable', 'receivable'], true);
    }

    protected function resolvePriority(?string $dueAt): string
    {
        if (! $dueAt) {
            return 'medium';
        }

        $due = Carbon::parse($dueAt);

        if ($due->isPast()) {
            return 'high';
        }

        return $due->isToday() ? 'high' : 'medium';
    }

    protected function buildReminderMessage(array $parsed): string
    {
        $type = Str::headline((string) ($parsed['type'] ?? $parsed['intent'] ?? 'entry'));
        $party = $parsed['counterparty_name'] ?? 'contact';
        $amount = isset($parsed['amount']) ? 'Rs. '.$parsed['amount'] : 'pending amount';

        return "{$type} reminder for {$party} ({$amount})";
    }
}
