<?php

namespace App\Services;

use App\Enums\Currency;
use App\Enums\PaymentStatus;
use App\Enums\SaleOrigin;
use App\Enums\SaleType;
use App\Models\Client;
use App\Models\Sale;
use App\Models\UpworkToken;
use App\Models\User;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

/**
 * ─── UPWORK ADAPTER — SKELETON MVP ─────────────────────────────────────────
 *
 * Estado: STUB — pendiente de conectar con la API real de Upwork.
 *
 * Para completar la integración real:
 * 1. Obtener credenciales en: https://www.upwork.com/developer/keys/apply
 * 2. Configurar en .env:
 *      UPWORK_CLIENT_ID=xxx
 *      UPWORK_CLIENT_SECRET=xxx
 *      UPWORK_REDIRECT_URI=http://localhost:8080/upwork/callback
 *
 * 3. En fetchContracts(): descomentar el bloque HTTP real y eliminar los datos simulados.
 * 4. En mapContractToSale(): completar el mapeo de campos según la respuesta real de la API.
 *
 * Referencia API: https://developers.upwork.com/
 * Endpoint contratos: GET /api/hr/v2/contracts
 * ────────────────────────────────────────────────────────────────────────────
 */
class UpworkAdapter
{
    private const API_BASE = 'https://www.upwork.com/api';

    public function __construct(private ?UpworkToken $token = null) {}

    /**
     * ── PASO 1: Generar URL de autorización OAuth2 ─────────────────────────
     * TODO: usar cuando el usuario conecte su cuenta Upwork.
     */
    public function getAuthorizationUrl(): string
    {
        $params = http_build_query([
            'response_type' => 'code',
            'client_id'     => config('services.upwork.client_id'),
            'redirect_uri'  => config('services.upwork.redirect_uri'),
            'scope'         => 'hr:read',
            'state'         => csrf_token(),
        ]);

        return "https://www.upwork.com/ab/account-security/oauth2/authorize?{$params}";
    }

    /**
     * ── PASO 2: Intercambiar code por access_token ─────────────────────────
     * TODO: llamar desde UpworkOAuthController::callback()
     */
    public function exchangeCodeForToken(string $code): array
    {
        // TODO: descomentar cuando tengas credenciales reales
        /*
        $response = Http::asForm()->post('https://www.upwork.com/api/v3/oauth2/token', [
            'grant_type'    => 'authorization_code',
            'code'          => $code,
            'client_id'     => config('services.upwork.client_id'),
            'client_secret' => config('services.upwork.client_secret'),
            'redirect_uri'  => config('services.upwork.redirect_uri'),
        ]);

        return $response->json();
        */

        // SIMULADO para MVP:
        return [
            'access_token'  => 'STUB_ACCESS_TOKEN',
            'refresh_token' => 'STUB_REFRESH_TOKEN',
            'expires_in'    => 86400,
            'token_type'    => 'Bearer',
        ];
    }

    /**
     * ── PASO 3: Obtener contratos de la semana pasada ─────────────────────
     * TODO: implementar llamada real a la API de Upwork.
     */
    public function fetchContracts(): array
    {
        if (!$this->token || $this->token->isExpired()) {
            Log::warning('UpworkAdapter: token no disponible o expirado.');
            return [];
        }

        // TODO: descomentar y ajustar cuando tengas credenciales reales.
        // Referencia: https://developers.upwork.com/#contracts
        /*
        $response = Http::withToken($this->token->access_token)
            ->get(self::API_BASE . '/hr/v2/contracts', [
                'buyer__reference' => 'me',
                'status'           => 'active',
            ]);

        if (!$response->ok()) {
            Log::error('UpworkAdapter: error al obtener contratos', $response->json());
            return [];
        }

        return $response->json('contracts.contract', []);
        */

        // SIMULADO para MVP — devuelve datos de prueba:
        Log::info('UpworkAdapter: usando datos SIMULADOS (stub).');
        return [
            [
                'reference'         => 'UPWORK-001',
                'title'             => 'Contrato simulado #1',
                'buyer_name'        => 'Cliente Upwork Demo',
                'buyer_reference'   => 'client-upwork-001',
                'weekly_stipend'    => 0,
                'hourly_rate'       => '25.00',
                'hours_worked'      => '10.0',
                'amount'            => '250.00',
                'currency'          => 'USD',
            ],
        ];
    }

    /**
     * ── PASO 4: Mapear un contrato de Upwork a un Sale en Nuna ───────────
     * Crea o actualiza la venta correspondiente.
     */
    public function mapContractToSale(array $contract, User $ownerUser): Sale
    {
        // Buscar o crear el cliente por external_id de Upwork
        $client = Client::firstOrCreate(
            ['contact_email' => 'upwork-' . ($contract['buyer_reference'] ?? 'unknown') . '@nuna.internal'],
            [
                'name'             => $contract['buyer_name'] ?? 'Cliente Upwork',
                'origin'           => 'upwork',
                'currency_default' => 'USD',
            ]
        );

        // Calcular gross_amount
        // TODO: usar el campo correcto de la respuesta real de la API.
        // El neto después del fee de Upwork no siempre está disponible directamente.
        // Upwork cobra ~20% en contratos nuevos. Ajustar según tu contrato real.
        $grossAmount = (float) ($contract['amount'] ?? 0);

        return Sale::updateOrCreate(
            [
                'external_source' => 'upwork',
                'external_id'     => $contract['reference'] ?? null,
            ],
            [
                'client_id'              => $client->id,
                'owner_user_id'          => $ownerUser->id,
                'created_by_user_id'     => $ownerUser->id,
                'origin'                 => SaleOrigin::Upwork->value,
                'sale_type'              => SaleType::Fixed->value,
                'title'                  => $contract['title'] ?? 'Contrato Upwork',
                'sale_date'              => now()->toDateString(),
                'currency'               => Currency::USD->value,
                'fixed_amount'           => $grossAmount,
                'gross_amount'           => $grossAmount,
                'payment_status'         => PaymentStatus::Unpaid->value,
                'collected_amount_cached' => 0,
            ]
        );
    }
}
