<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use DateTimeInterface;

class TrelloService
{
    protected string $apiKey;
    protected string $apiToken;
    protected string $boardId;
    protected string $baseUrl = 'https://api.trello.com/1';

    public function __construct()
    {
        $this->apiKey   = config('trello.api_key');
        $this->apiToken = config('trello.api_token');
        $this->boardId  = config('trello.board_id');
    }

    /* =====================================================
     |  Public API
     ===================================================== */

    /**
     * Create a new Trello card and populate base fields
     */
    public function createCard(
        string $orderId,
        string $orderNumber,
        string $orderType = 'standard',
        ?string $startingListId = null
    ): ?string {
        if (! $this->isConfigured()) {
            Log::warning('Trello not configured, skipping card creation');
            return null;
        }

        try {
            $listId = $startingListId ?? $this->getStartingListId($orderType);

            $response = Http::post("{$this->baseUrl}/cards", [
                'name'   => "Order #{$orderNumber}",
                'desc'   => "Order ID: {$orderId}\nType: {$orderType}",
                'idList' => $listId,
                'key'    => $this->apiKey,
                'token'  => $this->apiToken,
            ]);

            if (! $response->successful()) {
                Log::error('Failed to create Trello card', [
                    'response' => $response->body(),
                ]);
                return null;
            }

            $cardId = $response->json('id');

            if ($cardId) {
                $this->populateInitialFields($cardId, $orderId);
            }

            return $cardId;

        } catch (\Throwable $e) {
            Log::error('Exception creating Trello card', [
                'error' => $e->getMessage(),
            ]);
            return null;
        }
    }

    /**
     * Move card to another list
     */
    public function moveCard(string $cardId, string $listName): bool
    {
        if (! $this->isConfigured()) {
            return false;
        }

        $listId = $this->getListIdByName($listName);

        if (! $listId) {
            Log::warning('Trello list not found', ['list' => $listName]);
            return false;
        }

        $response = Http::put("{$this->baseUrl}/cards/{$cardId}", [
            'idList' => $listId,
            'key'    => $this->apiKey,
            'token'  => $this->apiToken,
        ]);

        return $response->successful();
    }

    /**
     * Attach a URL/file to a card
     */
    public function attachFile(string $cardId, string $name, string $url): bool
    {
        $response = Http::post("{$this->baseUrl}/cards/{$cardId}/attachments", [
            'name'  => $name,
            'url'   => $url,
            'key'   => $this->apiKey,
            'token' => $this->apiToken,
        ]);

        return $response->successful();
    }

    /**
     * Mark checklist item complete
     */
    public function checkItem(string $cardId, string $checklistName, string $itemName): bool
    {
        $card = Http::get("{$this->baseUrl}/cards/{$cardId}", [
            'checklists' => 'open',
            'key'        => $this->apiKey,
            'token'      => $this->apiToken,
        ])->json();

        $checklist = collect($card['checklists'] ?? [])
            ->firstWhere('name', $checklistName);

        if (! $checklist) {
            return false;
        }

        $item = collect($checklist['checkItems'] ?? [])
            ->firstWhere('name', $itemName);

        if (! $item) {
            return false;
        }

        $response = Http::put(
            "{$this->baseUrl}/checklists/{$checklist['id']}/checkItems/{$item['id']}",
            [
                'state' => 'complete',
                'key'   => $this->apiKey,
                'token' => $this->apiToken,
            ]
        );

        return $response->successful();
    }

    /* =====================================================
     |  Custom Fields
     ===================================================== */

    public function setTextField(string $cardId, string $fieldKey, string $value): bool
    {
        return $this->setCustomField($cardId, $fieldKey, ['text' => $value]);
    }

    public function setNumberField(string $cardId, string $fieldKey, float|int $value): bool
    {
        return $this->setCustomField($cardId, $fieldKey, ['number' => (string) $value]);
    }

    public function setDateField(string $cardId, string $fieldKey, DateTimeInterface $date): bool
    {
        return $this->setCustomField($cardId, $fieldKey, [
            'date' => $date->format(DATE_ATOM),
        ]);
    }

    protected function setCustomField(string $cardId, string $fieldKey, array $value): bool
    {
        $fieldId = config("trello.custom_fields.{$fieldKey}");

        if (! $fieldId) {
            Log::warning('Trello custom field not configured', ['field' => $fieldKey]);
            return false;
        }

        $response = Http::put(
            "{$this->baseUrl}/cards/{$cardId}/customField/{$fieldId}/item",
            [
                'value' => $value,
                'key'   => $this->apiKey,
                'token' => $this->apiToken,
            ]
        );

        return $response->successful();
    }

    /* =====================================================
     |  Internals
     ===================================================== */

    protected function populateInitialFields(string $cardId, string $orderId): void
    {
        $this->setTextField($cardId, 'order_id', $orderId);
        $this->setDateField($cardId, 'date_created', now());
    }

    protected function getStartingListId(string $orderType): string
    {
        return $orderType === 'custom'
            ? config('trello.lists.custom.new_custom_order')
            : config('trello.lists.standard.new_order');
    }

    protected function getListIdByName(string $listName): ?string
    {
        $lists = array_merge(
            config('trello.lists.standard', []),
            config('trello.lists.custom', [])
        );

        foreach ($lists as $key => $id) {
            if (strtolower(str_replace('_', ' ', $key)) === strtolower($listName)) {
                return $id;
            }
        }

        return null;
    }

    protected function isConfigured(): bool
    {
        return ! empty($this->apiKey)
            && ! empty($this->apiToken)
            && ! empty($this->boardId);
    }
}
