<?php
// includes/webhook-handler.php

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

/* ---------------------------------------------------------------------------
   REST endpoint: POST /wp-json/asana-automator/v1/webhook/{id}
   Handles Asana handshake + event delivery.
--------------------------------------------------------------------------- */

add_action('rest_api_init', function () {
    register_rest_route('asana-automator/v1', '/webhook/(?P<id>[a-zA-Z0-9_-]+)', [
        'methods'             => 'POST',
        'callback'            => 'asana_automator_handle_webhook_request',
        'permission_callback' => '__return_true', // Auth is done via HMAC, not WP caps
    ]);
});

/**
 * Main webhook entry point.
 * Handles both the initial Asana handshake and live event delivery.
 */
function asana_automator_handle_webhook_request(WP_REST_Request $request) {
    $webhook_id = sanitize_key($request->get_param('id'));
    $webhooks   = get_option('asana_automator_webhooks', []);

    if (!isset($webhooks[$webhook_id])) {
        return new WP_REST_Response('Not found', 404);
    }

    $config = $webhooks[$webhook_id];

    /* ── Asana handshake: first delivery carries X-Hook-Secret ── */
    $hook_secret = $request->get_header('X_Hook_Secret');
    if (!empty($hook_secret)) {
        // Store the secret Asana issued us, then echo it back to confirm
        $config['secret']           = sanitize_text_field($hook_secret);
        $config['handshake_status'] = 'confirmed';

        // If registration deferred Asana GID persistence to avoid races,
        // hydrate it now during the successful handshake.
        $pending_gids = get_option('asana_automator_webhook_pending_gids', []);
        if (is_array($pending_gids) && empty($config['asana_gid']) && !empty($pending_gids[$webhook_id])) {
            $config['asana_gid'] = sanitize_text_field((string)$pending_gids[$webhook_id]);
            unset($pending_gids[$webhook_id]);
            update_option('asana_automator_webhook_pending_gids', $pending_gids);
        }

        $webhooks[$webhook_id]      = $config;
        update_option('asana_automator_webhooks', $webhooks);

        return new WP_REST_Response(null, 200, ['X-Hook-Secret' => $hook_secret]);
    }

    /* ── Subsequent deliveries: verify HMAC signature ── */
    $stored_secret = $config['secret'] ?? '';
    if (empty($stored_secret)) {
        // Webhook registered but handshake not yet completed
        return new WP_REST_Response('Handshake pending', 400);
    }

    $body      = $request->get_body();
    $signature = $request->get_header('X_Hook_Signature');
    $expected  = hash_hmac('sha256', $body, $stored_secret);

    if (!hash_equals($expected, (string) $signature)) {
        return new WP_REST_Response('Invalid signature', 400);
    }

    /* ── Resolve PAT token ── */
    $pat_label    = $config['pat_label'] ?? '';
    $token = asana_automator_get_pat_token($pat_label);

    if (empty($token)) {
        return new WP_REST_Response('No PAT token available', 500);
    }

    /* ── Process each event ── */
    $payload = json_decode($body, true);
    foreach ($payload['events'] ?? [] as $event) {
        asana_automator_process_webhook_event($event, $config, $token);
    }

    return new WP_REST_Response('OK', 200);
}

/**
 * Process a single Asana event.
 * Handles:
 * - task completion changes
 * - story/comment events (for client comment email notifications)
 */
function asana_automator_process_webhook_event(array $event, array $config, string $token) {
    asana_automator_webhook_process_completion_event($event, $config, $token);
    asana_automator_webhook_process_story_comment_event($event, $config, $token);
}

function asana_automator_webhook_fetch_task(string $task_gid, string $token, string $opt_fields): array {
    if ($task_gid === '') {
        return [];
    }

    $res = wp_remote_get(
        "https://app.asana.com/api/1.0/tasks/{$task_gid}?opt_fields={$opt_fields}",
        ['headers' => ['Authorization' => 'Bearer ' . $token]]
    );

    if (is_wp_error($res)) {
        return [];
    }

    return (array)(json_decode(wp_remote_retrieve_body($res), true)['data'] ?? []);
}

function asana_automator_webhook_fetch_story(string $story_gid, string $token): array {
    if ($story_gid === '') {
        return [];
    }

    $fields = 'gid,text,type,resource_subtype,created_at,created_by.gid,created_by.name,target.gid,target.resource_type';
    $res = wp_remote_get(
        "https://app.asana.com/api/1.0/stories/{$story_gid}?opt_fields={$fields}",
        ['headers' => ['Authorization' => 'Bearer ' . $token]]
    );

    if (is_wp_error($res)) {
        return [];
    }

    return (array)(json_decode(wp_remote_retrieve_body($res), true)['data'] ?? []);
}

function asana_automator_webhook_process_completion_event(array $event, array $config, string $token): void {
    $log_file = WP_CONTENT_DIR . '/custom-debug.log';

    // Only care about task completion changes
    if (($event['resource']['resource_type'] ?? '') !== 'task') return;
    if (($event['action'] ?? '')                             !== 'changed') return;
    if (($event['change']['field'] ?? '')                    !== 'completed') return;
    if (($event['change']['new_value'] ?? false)             !== true) return;

    $task_gid = $event['resource']['gid'] ?? '';
    if (empty($task_gid)) return;

    file_put_contents($log_file,
        date('c') . " 🔔 Webhook: task {$task_gid} marked complete — fetching full task\n",
        FILE_APPEND);

    // Fetch full task to confirm it's actually complete and evaluate cleanup rules
    $task = asana_automator_webhook_fetch_task(
        $task_gid,
        $token,
        'gid,name,notes,completed,projects.gid,projects.name,memberships.section.gid,memberships.section.name,memberships.project.gid,custom_fields.gid,custom_fields.name,custom_fields.text_value,custom_fields.display_value,custom_fields.number_value'
    );

    if (empty($task)) {
        file_put_contents($log_file,
            date('c') . " ❌ Webhook: failed to fetch task {$task_gid}\n",
            FILE_APPEND);
        return;
    }

    if (empty($task) || empty($task['completed'])) return;

    $ran_cleanup_rule = false;
    $rules = get_option('asana_automator_rules', []);
    foreach ($rules as $rule) {
        if (!asana_automator_webhook_rule_matches_task($rule, $task)) {
            continue;
        }

        $action = (string)($rule['action'] ?? '');
        if ($action === 'cleanup_on_completion') {
            asana_automator_cleanup_on_completion($rule, $token, $task);
            $ran_cleanup_rule = true;
            continue;
        }

        if ($action === 'email_client_gateway_on_completion' && function_exists('asana_automator_email_client_gateway_on_completion')) {
            try {
                asana_automator_email_client_gateway_on_completion($rule, $token, $task);
            } catch (Throwable $e) {
                file_put_contents(
                    $log_file,
                    date('c') . " ❌ Completion gateway email webhook error for task {$task_gid}: " . $e->getMessage() . "\n",
                    FILE_APPEND
                );
            }
        }
    }

    // Backward-compatible fallback for older webhook-only setups.
    if (!$ran_cleanup_rule && function_exists('asana_automator_delete_attachments_on_complete')) {
        asana_automator_delete_attachments_on_complete($config, $token, $task);
    }
}

function asana_automator_webhook_process_story_comment_event(array $event, array $config, string $token): void {
    $log_file = WP_CONTENT_DIR . '/custom-debug.log';

    if (($event['resource']['resource_type'] ?? '') !== 'story') {
        return;
    }

    if (($event['action'] ?? '') !== 'added') {
        return;
    }

    $story_gid = trim((string)($event['resource']['gid'] ?? ''));
    if ($story_gid === '') {
        return;
    }

    $story = asana_automator_webhook_fetch_story($story_gid, $token);
    if (empty($story)) {
        file_put_contents($log_file, date('c') . " ⚠️ Webhook story fetch failed for {$story_gid}\n", FILE_APPEND);
        return;
    }

    $story_subtype = strtolower(trim((string)($story['resource_subtype'] ?? $story['type'] ?? '')));
    if ($story_subtype !== '' && strpos($story_subtype, 'comment') === false) {
        return;
    }

    $task_gid = trim((string)($event['parent']['gid'] ?? ''));
    if ($task_gid === '') {
        $task_gid = trim((string)($story['target']['gid'] ?? ''));
    }
    if ($task_gid === '') {
        return;
    }

    $task = asana_automator_webhook_fetch_task(
        $task_gid,
        $token,
        'gid,name,completed,projects.gid,projects.name,memberships.section.gid,memberships.section.name,memberships.project.gid,custom_fields.gid,custom_fields.name,custom_fields.text_value,custom_fields.display_value'
    );
    if (empty($task)) {
        file_put_contents($log_file, date('c') . " ⚠️ Webhook could not load task {$task_gid} for story {$story_gid}\n", FILE_APPEND);
        return;
    }

    $rules = get_option('asana_automator_rules', []);
    foreach ($rules as $rule) {
        if (($rule['action'] ?? '') !== 'email_client_on_new_team_comment') {
            continue;
        }

        if (!asana_automator_webhook_rule_matches_task($rule, $task)) {
            continue;
        }

        if (!function_exists('asana_automator_email_client_on_new_team_comment')) {
            file_put_contents($log_file, date('c') . " ⚠️ Missing comment email handler function\n", FILE_APPEND);
            return;
        }

        try {
            asana_automator_email_client_on_new_team_comment($rule, $token, $task, $story);
        } catch (Throwable $e) {
            file_put_contents(
                $log_file,
                date('c') . " ❌ Comment email webhook error for task {$task_gid}, story {$story_gid}: " . $e->getMessage() . "\n",
                FILE_APPEND
            );
        }
    }
}

function asana_automator_webhook_rule_matches_task(array $rule, array $task): bool {
    $rule_project_gid = trim((string)($rule['project_gid'] ?? ''));
    $task_project_gids = [];
    foreach ((array)($task['projects'] ?? []) as $project) {
        $gid = trim((string)($project['gid'] ?? ''));
        if ($gid !== '') {
            $task_project_gids[] = $gid;
        }
    }

    if ($rule_project_gid !== '' && !in_array($rule_project_gid, $task_project_gids, true)) {
        return false;
    }

    $rule_section_gids = array_values(array_filter(array_map('trim', (array)($rule['section_gids'] ?? []))));
    if (empty($rule_section_gids)) {
        return true;
    }

    $task_section_gids = [];
    foreach ((array)($task['memberships'] ?? []) as $membership) {
        $section_gid = trim((string)($membership['section']['gid'] ?? ''));
        if ($section_gid !== '') {
            $task_section_gids[] = $section_gid;
        }
    }

    foreach ($rule_section_gids as $rule_section_gid) {
        if (in_array($rule_section_gid, $task_section_gids, true)) {
            return true;
        }
    }

    return false;
}
