<?php

namespace OtomaticAi\Models\Usages;

use OtomaticAi\Vendors\Carbon\Carbon;
use OtomaticAi\Vendors\Carbon\CarbonPeriod;
use OtomaticAi\Vendors\Illuminate\Database\Capsule\Manager as Database;
use OtomaticAi\Vendors\Illuminate\Support\Arr;

class OpenAIChatUsage extends Usage
{
    static private $prices = [
        // gpt-3.5-turbo
        [
            'model' => 'gpt-3.5-turbo',
            'default' => true,
            'prompt' => 0.50,
            'completion' => 1.50,
        ],
        [
            'model' => 'gpt-3.5-turbo-0613',
            'prompt' => 1.50,
            'completion' => 2.00,
        ],
        [
            'model' => 'gpt-3.5-turbo-1106',
            'prompt' => 1.00,
            'completion' => 2.00,
        ],
        [
            'model' => 'gpt-3.5-turbo-0125',
            'prompt' => 0.50,
            'completion' => 1.50,
        ],

        // gpt-3.5-turbo-16k
        [
            'model' => 'gpt-3.5-turbo-16k',
            'default' => true,
            'prompt' => 3,
            'completion' => 4,
        ],
        [
            'model' => 'gpt-3.5-turbo-16k-0613',
            'prompt' => 3.00,
            'completion' => 4.00,
        ],

        // gpt-4
        [
            'model' => 'gpt-4',
            'default' => true,
            'prompt' => 30,
            'completion' => 60,
        ],
        [
            'model' => 'gpt-4-0314',
            'prompt' => 30,
            'completion' => 60,
        ],
        [
            'model' => 'gpt-4-0613',
            'prompt' => 30,
            'completion' => 60,
        ],

        // gpt-4-turbo
        [
            'model' => 'gpt-4-turbo-preview',
            'default' => true,
            'prompt' => 10,
            'completion' => 30,
        ],
        [
            'model' => 'gpt-4-1106-preview',
            'prompt' => 10,
            'completion' => 30,
        ],
        [
            'model' => 'gpt-4-0125-preview',
            'prompt' => 10,
            'completion' => 30,
        ],
        [
            'model' => 'gpt-4-turbo-2024-04-09',
            'prompt' => 10,
            'completion' => 30,
        ],

        // gpt-4-32k
        [
            'model' => 'gpt-4-32k',
            'prompt' => 60,
            'completion' => 120,
        ],

        // gpt-4o
        [
            'model' => 'gpt-4o',
            'default' => true,
            'prompt' => 2.50,
            'completion' => 10,
        ],
        [
            'model' => 'gpt-4o-2024-05-13',
            'prompt' => 5,
            'completion' => 15,
        ],
        [
            'model' => 'gpt-4o-2024-08-06',
            'prompt' => 2.50,
            'completion' => 10,
        ],
        [
            'model' => 'gpt-4o-2024-11-20',
            'prompt' => 2.50,
            'completion' => 10,
        ],

        // GPT-4o Mini
        [
            'model' => 'gpt-4o-mini',
            'default' => true,
            'prompt' => 0.15,
            'completion' => 0.6,
        ],
        [
            'model' => 'gpt-4o-mini-2024-07-18',
            'prompt' => 0.15,
            'completion' => 0.6,
        ],

        // gpt-4-1
        [
            'model' => 'gpt-4.1-2025-04-14',
            'prompt' => 2,
            'completion' => 8,
        ],
        [
            'model' => 'gpt-4.1-mini-2025-04-14',
            'prompt' => 0.4,
            'completion' => 1.6,
        ],
        [
            'model' => 'gpt-4.1-nano-2025-04-14',
            'prompt' => 0.1,
            'completion' => 0.4,
        ],

        // gpt-4-5
        [
            'model' => 'gpt-4.5-preview-2025-02-27',
            'prompt' => 75,
            'completion' => 150,
        ],

        // gpt-5
        [
            'model' => 'gpt-5-nano',
            'default' => true,
            'prompt' => 0.05,
            'completion' => 0.4,
        ],
        [
            'model' => 'gpt-5-nano-2025-08-07',
            'prompt' => 0.05,
            'completion' => 0.4,
        ],
        [
            'model' => 'gpt-5-mini',
            'default' => true,
            'prompt' => 0.25,
            'completion' => 2,
        ],
        [
            'model' => 'gpt-5-mini-2025-08-07',
            'prompt' => 0.25,
            'completion' => 2,
        ],
        [
            'model' => 'gpt-5',
            'default' => true,
            'prompt' => 1.25,
            'completion' => 10,
        ],
        [
            'model' => 'gpt-5-2025-08-07',
            'prompt' => 1.25,
            'completion' => 10,
        ],
        [
            'model' => 'gpt-5.1',
            'default' => true,
            'prompt' => 1.25,
            'completion' => 10,
        ],
        [
            'model' => 'gpt-5.1-2025-11-13',
            'prompt' => 1.25,
            'completion' => 10,
        ],
        [
            'model' => 'gpt-5.2',
            'default' => true,
            'prompt' => 1.75,
            'completion' => 14,
        ],
        [
            'model' => 'gpt-5.2-2025-12-11',
            'prompt' => 1.75,
            'completion' => 14,
        ],
        [
            'model' => 'gpt-5.2-pro',
            'default' => true,
            'prompt' => 21,
            'completion' => 168,
        ],
        [
            'model' => 'gpt-5.2-pro-2025-12-11',
            'prompt' => 21,
            'completion' => 168,
        ],

        // o1
        [
            'model' => 'o1',
            'default' => true,
            'prompt' => 15,
            'completion' => 60,
        ],
        [
            'model' => 'o1-2024-12-17',
            'prompt' => 15,
            'completion' => 60,
        ],
        [
            'model' => 'o1-preview-2024-09-12',
            'prompt' => 15,
            'completion' => 60,
        ],

        // o1-mini
        [
            'model' => 'o1-mini',
            'default' => true,
            'prompt' => 1.10,
            'completion' => 4.40,
        ],
        [
            'model' => 'o1-mini-2024-09-12',
            'prompt' => 1.10,
            'completion' => 4.40,
        ],

        // o3
        [
            'model' => 'o3',
            'default' => true,
            'prompt' => 10,
            'completion' => 40,
        ],
        [
            'model' => 'o3-2025-04-16',
            'prompt' => 2,
            'completion' => 8,
        ],

        // o3-mini
        [
            'model' => 'o3-mini',
            'default' => true,
            'prompt' => 1.10,
            'completion' => 4.40,
        ],
        [
            'model' => 'o3-mini-2025-01-31',
            'prompt' => 1.10,
            'completion' => 4.40,
        ],

        // o4-mini
        [
            'model' => 'o4-mini',
            'default' => true,
            'prompt' => 1.10,
            'completion' => 4.40,
        ],
        [
            'model' => 'o4-mini-2025-04-16',
            'prompt' => 1.10,
            'completion' => 4.40,
        ],

    ];

    /**
     * Get a new query builder for the model's table.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function newQuery()
    {
        return $this->registerGlobalScopes($this->newQueryWithoutScopes())
            ->where('provider', 'openai_chat');
    }

    static public function monthly(int $months = 12, int $diff = 0)
    {
        $start = Carbon::now()->subMonth($months - 1)->startOfMonth();
        $stop = Carbon::now()->subMonth($diff)->endOfMonth();
        $usages = self::query()
            ->select([
                Database::raw("DATE_FORMAT(created_at, '%Y-%m') as 'month_date'"),
                Database::raw("JSON_UNQUOTE(JSON_EXTRACT(payload, '$.model')) as 'model'"),
                Database::raw("SUM(JSON_UNQUOTE(JSON_EXTRACT(payload, '$.prompt_tokens'))) as 'prompt_tokens'"),
                Database::raw("SUM(JSON_UNQUOTE(JSON_EXTRACT(payload, '$.completion_tokens'))) as 'completion_tokens'"),
            ])
            ->groupBy([
                Database::raw("DATE_FORMAT(created_at, '%Y-%m')"),
                'model'
            ])
            ->whereBetween('created_at', [$start, $stop])
            ->get();

        $usages = $usages->groupBy(['month_date', 'model']);

        $output = [];
        $period = CarbonPeriod::since($start)->month()->until($stop);
        foreach ($period as $date) {
            $date = $date->format('Y-m');

            $o = [
                "amount" => 0,
                "details" => [],
            ];

            if ($usages->has($date)) {
                foreach ($usages->get($date) as $model => $usagesForModel) {
                    if (!isset($o["details"][$model])) {
                        $o["details"][$model] = 0;
                    }
                    foreach ($usagesForModel as $usage) {
                        $o["details"][$model] += self::calculateCosts($model, $usage->prompt_tokens, $usage->completion_tokens);
                    }

                    $o["amount"] += $o["details"][$model];
                }
            }

            $output[$date] = $o;
        }

        return $output;
    }

    static private function calculateCosts($model, $promptTokens, $completionTokens)
    {
        $amount = 0;
        $costs = Arr::keyBy(self::$prices, 'model');
        $costs = Arr::get($costs, $model, ['prompt' => 0, 'completion' => 0]);

        $amount = $promptTokens / 1000000 * $costs['prompt'];
        $amount = $amount + ($completionTokens / 1000000 * $costs['completion']);

        return $amount;
    }
}
