<?php

namespace App\Services;

use Illuminate\Http\Client\Factory as HttpFactory;
use Illuminate\Support\Arr;

class OpenAiSmartEntryParser
{
    public function __construct(
        protected HttpFactory $http,
    ) {}

    public function isConfigured(): bool
    {
        return filled(config('services.openai.api_key'));
    }

    public function parse(string $input, string $source = 'ai_text'): ?array
    {
        if (! $this->isConfigured()) {
            return null;
        }

        $response = $this->http
            ->baseUrl(rtrim((string) config('services.openai.base_url'), '/'))
            ->withToken((string) config('services.openai.api_key'))
            ->acceptJson()
            ->timeout(20)
            ->post('/responses', [
                'model' => config('services.openai.model', 'gpt-4o-mini'),
                'input' => [
                    [
                        'role' => 'system',
                        'content' => [
                            [
                                'type' => 'input_text',
                                'text' => $this->systemPrompt($source),
                            ],
                        ],
                    ],
                    [
                        'role' => 'user',
                        'content' => [
                            [
                                'type' => 'input_text',
                                'text' => $input,
                            ],
                        ],
                    ],
                ],
                'text' => [
                    'format' => [
                        'type' => 'json_schema',
                        'name' => 'smart_entry',
                        'schema' => $this->schema(),
                        'strict' => true,
                    ],
                ],
            ]);

        if (! $response->successful()) {
            return null;
        }

        $payload = $response->json();
        $outputText = $payload['output_text'] ?? null;

        if (! is_string($outputText) || blank($outputText)) {
            $outputText = Arr::get($payload, 'output.0.content.0.text');
        }

        if (! is_string($outputText) || blank($outputText)) {
            return null;
        }

        $decoded = json_decode($outputText, true);

        return is_array($decoded) ? $decoded : null;
    }

    protected function systemPrompt(string $source): string
    {
        $today = now()->format('Y-m-d');
        $time = now()->format('H:i');

        return <<<PROMPT
You convert natural language money notes into structured finance actions for Flowieons.

Current date: {$today}
Current time: {$time}
Input source: {$source}

Return only valid JSON matching the schema.

Rules:
- Detect one primary type: expense, income, payable, or receivable.
- Convert relative dates like tomorrow using the current date.
- If payable or receivable has no time, default due_at to 18:00:00 local time.
- Keep category broad and subcategory specific when possible.
- If the note mentions business or work, use purpose business. Otherwise use personal unless strongly implied.
- direction is in for income and receivable, out for expense and payable.
- status is pending for payable or receivable, posted otherwise.
- source must be exactly "{$source}".
PROMPT;
    }

    protected function schema(): array
    {
        return [
            'type' => 'object',
            'additionalProperties' => false,
            'properties' => [
                'type' => [
                    'type' => 'string',
                    'enum' => ['expense', 'income', 'payable', 'receivable'],
                ],
                'amount' => [
                    'type' => ['number', 'null'],
                ],
                'counterparty_name' => [
                    'type' => ['string', 'null'],
                ],
                'counterparty_mobile' => [
                    'type' => ['string', 'null'],
                ],
                'category' => [
                    'type' => ['string', 'null'],
                ],
                'subcategory' => [
                    'type' => ['string', 'null'],
                ],
                'purpose' => [
                    'type' => ['string', 'null'],
                    'enum' => ['business', 'personal', 'work', null],
                ],
                'date' => [
                    'type' => ['string', 'null'],
                    'description' => 'YYYY-MM-DD',
                ],
                'due_at' => [
                    'type' => ['string', 'null'],
                    'description' => 'YYYY-MM-DD HH:MM:SS',
                ],
                'direction' => [
                    'type' => 'string',
                    'enum' => ['in', 'out'],
                ],
                'status' => [
                    'type' => 'string',
                    'enum' => ['posted', 'pending', 'settled'],
                ],
                'source' => [
                    'type' => 'string',
                    'enum' => ['ai_text', 'voice'],
                ],
                'note' => [
                    'type' => ['string', 'null'],
                ],
            ],
            'required' => [
                'type',
                'amount',
                'counterparty_name',
                'counterparty_mobile',
                'category',
                'subcategory',
                'purpose',
                'date',
                'due_at',
                'direction',
                'status',
                'source',
                'note',
            ],
        ];
    }
}
