<?php

namespace EasyLinkAutomations\Actions\Notion;

if (!defined('ABSPATH')) {
    exit;
}

use EasyLinkAutomations\Actions\BaseAction;
use EasyLinkAutomations\Models\Connection;

/**
 * Action that creates a new page inside a Notion database.
 *
 * Migrated from n8n: Notion v2 (resource: databasePage, operation: create)
 * Uses Notion API v1 to create a database page with property mapping.
 */
final class DatabasePageCreateAction extends BaseAction
{
    private const API_BASE    = 'https://api.notion.com/v1';
    private const API_VERSION = '2022-06-28';

    public static function getSlug(): string
    {
        return 'notion/database_page_create';
    }

    public static function getName(): string
    {
        return __('Create Database Page', 'easylink-automations');
    }

    public static function getDescription(): string
    {
        return __('Create a new page (record) in a Notion database', 'easylink-automations');
    }

    public static function getCategory(): string
    {
        return 'Notion';
    }

    public static function getIcon(): string
    {
        return 'notion';
    }


    public static function getRequiresConnection(): ?string
    {
        return 'notion';
    }

    public static function getConfigFields(): array
    {
        return [
            'database_id' => [
                'label'         => 'Database',
                'type'          => 'remote_select',
                'required'      => true,
                'placeholder'   => 'Select a database...',
                'remote_source' => 'notion/databases',
                'depends_on'    => ['connection_id'],
                'options_key'   => 'databases',
            ],
            'properties' => [
                'label'            => 'Properties',
                'type'             => 'field_mapping',
                'required'         => true,
                'remote_source'    => 'notion/database-properties',
                'depends_on'       => ['connection_id', 'database_id'],
                'options_key'      => 'columns',
                'supports_mapping' => true,
            ],
        ];
    }

    public function execute(array $triggerData, array $config): array
    {
        $missing = $this->validateRequired($config);
        if ($missing) {
            return ['success' => false, 'message' => 'Missing required fields: ' . implode(', ', $missing)];
        }

        $connectionId = (int) ($config['connection_id'] ?? 0);
        $token        = Connection::getAccessToken($connectionId);
        if (empty($token)) {
            return ['success' => false, 'message' => 'No valid Notion connection found or token expired'];
        }

        $mapped     = $this->mapConfig($config, $triggerData);
        $databaseId = trim($config['database_id'] ?? '');

        if (empty($databaseId)) {
            return ['success' => false, 'message' => 'Database is required'];
        }

        // Decode field_mapping data
        $fields = $mapped['properties'] ?? '{}';
        if (is_string($fields)) {
            $fields = json_decode($fields, true);
        }
        if (!is_array($fields)) {
            $fields = [];
        }

        $headers = [
            'Content-Type'   => 'application/json',
            'Authorization'  => 'Bearer ' . $token,
            'Notion-Version' => self::API_VERSION,
        ];

        // Fetch database schema to get property types
        $schemaUrl  = self::API_BASE . '/databases/' . rawurlencode($databaseId);
        $schemaResp = wp_remote_get($schemaUrl, ['headers' => $headers, 'timeout' => 15]);
        if (is_wp_error($schemaResp)) {
            return ['success' => false, 'message' => 'Failed to fetch database schema: ' . $schemaResp->get_error_message()];
        }

        $schemaCode = wp_remote_retrieve_response_code($schemaResp);
        $schema     = json_decode(wp_remote_retrieve_body($schemaResp), true);
        if ($schemaCode < 200 || $schemaCode >= 300) {
            return [
                'success' => false,
                'message' => 'Failed to fetch database schema (HTTP ' . $schemaCode . '): ' . ($schema['message'] ?? 'Unknown error'),
            ];
        }

        $schemaProp = $schema['properties'] ?? [];

        // Build properties payload
        $properties = [];
        foreach ($fields as $propName => $value) {
            if ($value === '' || $value === null) {
                continue;
            }
            $type      = $schemaProp[$propName]['type'] ?? 'rich_text';
            $formatted = $this->formatProperty($type, (string) $value);
            if ($formatted !== null) {
                $properties[$propName] = $formatted;
            }
        }

        $body = [
            'parent'     => ['database_id' => $databaseId],
            'properties' => $properties,
        ];

        $response = wp_remote_request(self::API_BASE . '/pages', [
            'method'  => 'POST',
            'headers' => $headers,
            'body'    => wp_json_encode($body),
            'timeout' => 30,
        ]);

        if (is_wp_error($response)) {
            return ['success' => false, 'message' => 'Request failed: ' . $response->get_error_message()];
        }

        $statusCode   = wp_remote_retrieve_response_code($response);
        $responseBody = json_decode(wp_remote_retrieve_body($response), true);
        $success      = $statusCode >= 200 && $statusCode < 300;

        return [
            'success' => $success,
            'message' => $success
                ? 'Database page created successfully'
                : 'Failed to create database page (HTTP ' . $statusCode . '): ' . ($responseBody['message'] ?? 'Unknown error'),
            'data'    => $responseBody ?? [],
        ];
    }

    /**
     * Format a property value according to its Notion property type.
     *
     * @return array|null Formatted property value, or null if type is unsupported
     */
    private function formatProperty(string $type, string $value): ?array
    {
        switch ($type) {
            case 'title':
                return ['title' => [['type' => 'text', 'text' => ['content' => $value]]]];

            case 'rich_text':
                return ['rich_text' => [['type' => 'text', 'text' => ['content' => $value]]]];

            case 'number':
                return is_numeric($value) ? ['number' => (float) $value] : null;

            case 'url':
                return ['url' => $value];

            case 'email':
                return ['email' => $value];

            case 'phone_number':
                return ['phone_number' => $value];

            case 'checkbox':
                return ['checkbox' => in_array(strtolower($value), ['true', '1', 'yes', 'on'], true)];

            case 'date':
                return ['date' => ['start' => $value]];

            case 'select':
                return ['select' => ['name' => $value]];

            case 'status':
                return ['status' => ['name' => $value]];

            case 'multi_select':
                $names = array_filter(array_map('trim', explode(',', $value)));
                return ['multi_select' => array_map(static fn ($n) => ['name' => $n], array_values($names))];

            case 'relation':
                $ids = array_filter(array_map('trim', explode(',', $value)));
                return ['relation' => array_map(static fn ($id) => ['id' => $id], array_values($ids))];

            case 'people':
                $ids = array_filter(array_map('trim', explode(',', $value)));
                return ['people' => array_map(static fn ($id) => ['object' => 'user', 'id' => $id], array_values($ids))];

            case 'files':
                return $this->formatFilesProperty($value);

            default:
                return null;
        }
    }

    private function formatFilesProperty(string $value): ?array
    {
        $decoded = json_decode($value, true);
        $items   = is_array($decoded) ? $decoded : array_filter(array_map('trim', explode(',', $value)));
        $files   = [];

        foreach ($items as $item) {
            $file = $this->formatFileItem($item);
            if ($file !== null) {
                $files[] = $file;
            }
        }

        return $files ? ['files' => $files] : null;
    }

    /**
     * @param mixed $item
     */
    private function formatFileItem($item): ?array
    {
        if (is_string($item)) {
            $url = trim($item);
            if ($url === '') {
                return null;
            }

            return [
                'name'     => $this->fileNameFromUrl($url),
                'type'     => 'external',
                'external' => ['url' => $url],
            ];
        }

        if (!is_array($item)) {
            return null;
        }

        $url = $item['external']['url'] ?? $item['url'] ?? '';
        $url = is_string($url) ? trim($url) : '';
        if ($url === '') {
            return null;
        }

        return [
            'name'     => is_string($item['name'] ?? null) && $item['name'] !== '' ? $item['name'] : $this->fileNameFromUrl($url),
            'type'     => 'external',
            'external' => ['url' => $url],
        ];
    }

    private function fileNameFromUrl(string $url): string
    {
        $path = parse_url($url, PHP_URL_PATH);
        $name = is_string($path) ? basename($path) : '';

        return $name !== '' ? $name : 'External file';
    }
}
