<?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 AnthropicUsage extends Usage
{
    static private $prices = [
        // claude 3 haiku
        [
            'model' => 'claude-3-haiku-20240307',
            'input' => 0.25, // per million tokens
            'output' => 1.25 // per million tokens
        ],

        // claude 3.5 haiku
        [
            'model' => 'claude-3-5-haiku-20241022',
            'input' => 0.8, // per million tokens
            'output' => 4 // per million tokens
        ],

        // claude 4.5 haiku
        [
            'model' => 'claude-haiku-4-5-20251001',
            'input' => 1, // per million tokens
            'output' => 5 // per million tokens
        ],

        // claude 3 sonnet
        [
            'model' => 'claude-3-sonnet-20240229',
            'input' => 3, // per million tokens
            'output' => 15 // per million tokens
        ],

        // claude 3.5 sonnet
        [
            'model' => 'claude-3-5-sonnet-20240620',
            'input' => 3, // per million tokens
            'output' => 15 // per million tokens
        ],
        [
            'model' => 'claude-3-5-sonnet-20241022',
            'input' => 3, // per million tokens
            'output' => 15 // per million tokens
        ],

        // claude 3.7 sonnet
        [
            'model' => 'claude-3-7-sonnet-20250219',
            'input' => 3, // per million tokens
            'output' => 15 // per million tokens
        ],

        // claude 3 opus
        [
            'model' => 'claude-3-opus-2024022',
            'input' => 15, // per million tokens
            'output' => 75 // per million tokens
        ],

        // claude 4 sonnet
        [
            'model' => 'claude-sonnet-4-20250514',
            'input' => 3, // per million tokens
            'output' => 15 // per million tokens
        ],

        // claude 4.5 sonnet
        [
            'model' => 'claude-sonnet-4-5-20250929',
            'input' => 3, // per million tokens
            'output' => 15 // per million tokens
        ],

        // claude 4.6 sonnet
        [
            'model' => 'claude-sonnet-4-6',
            'input' => 3, // per million tokens
            'output' => 15 // per million tokens
        ],

        // claude 5 sonnet
        [
            'model' => 'claude-sonnet-5',
            'input' => 3, // per million tokens
            'output' => 15 // per million tokens
        ],

        // claude 4 opus
        [
            'model' => 'claude-opus-4-20250514',
            'input' => 15, // per million tokens
            'output' => 75 // per million tokens
        ],

        // claude 4.1 opus
        [
            'model' => 'claude-opus-4-1-20250805',
            'input' => 15, // per million tokens
            'output' => 75 // per million tokens
        ],

        // claude 4.5 opus
        [
            'model' => 'claude-opus-4-5-20251101',
            'input' => 5, // per million tokens
            'output' => 25 // per million tokens
        ],

        // claude 4.6 opus
        [
            'model' => 'claude-opus-4-6',
            'input' => 5, // per million tokens
            'output' => 25 // per million tokens
        ],

        // claude 4.7 opus
        [
            'model' => 'claude-opus-4-7',
            'input' => 5, // per million tokens
            'output' => 25 // per million tokens
        ],

        // claude 4.8 opus
        [
            'model' => 'claude-opus-4-8',
            'input' => 5, // per million tokens
            'output' => 25 // per million tokens
        ],

        // claude 5 opus
        [
            'model' => 'claude-opus-5',
            'input' => 5, // per million tokens
            'output' => 25 // per million tokens
        ],
    ];

    /**
     * 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', 'anthropic_messages');
    }

    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, '$.input_tokens'))) as 'input_tokens'"),
                Database::raw("SUM(JSON_UNQUOTE(JSON_EXTRACT(payload, '$.output_tokens'))) as 'output_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->input_tokens, $usage->output_tokens);
                    }

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

            $output[$date] = $o;
        }

        return $output;
    }

    static private function calculateCosts($model, $inputTokens, $outputTokens)
    {
        $amount = 0;
        $costs = Arr::keyBy(self::$prices, 'model');
        $costs = Arr::get($costs, $model, ['input' => 0, 'output' => 0]);

        $amount = $inputTokens / 1000000 * $costs['input'];
        $amount = $amount + ($outputTokens / 1000000 * $costs['output']);

        return $amount;
    }
}
