<?php
if (!defined('ABSPATH')) exit;

require_once __DIR__ . '/../lib/status-store.php';
require_once __DIR__ . '/../lib/asana-client.php';

if (!function_exists('afb_normalize_upload_accept_tokens_from_csv')) {
    function afb_normalize_upload_accept_tokens_from_csv($raw_accept) {
        $parts = preg_split('/\s*,\s*/', strtolower((string) $raw_accept));
        if (!is_array($parts)) {
            return [];
        }

        $out = [];
        $seen = [];
        foreach ($parts as $part) {
            $token = trim((string) $part);
            if ($token === '') {
                continue;
            }

            $token = preg_replace('/\s+/', '', $token);
            if ($token === '') {
                continue;
            }

            if (strpos($token, '.') === 0) {
                $ext = preg_replace('/[^a-z0-9]/', '', substr($token, 1));
                if ($ext === '') {
                    continue;
                }

                $token = '.' . $ext;
            } elseif (preg_match('/^[a-z0-9!#$&^_.+-]+\/(?:[a-z0-9!#$&^_.+-]+|\*)$/', $token)) {
                // Valid MIME token.
            } elseif (preg_match('/^[a-z0-9]{1,16}$/', $token)) {
                $token = '.' . $token;
            } else {
                continue;
            }

            if (!isset($seen[$token])) {
                $seen[$token] = true;
                $out[] = $token;
            }
        }

        return $out;
    }
}

if (!function_exists('afb_file_matches_upload_accept_tokens')) {
    function afb_file_matches_upload_accept_tokens($file_name, $file_mime, $accept_tokens) {
        $tokens = is_array($accept_tokens) ? $accept_tokens : [];
        if (empty($tokens)) {
            return true;
        }

        $name = strtolower((string) $file_name);
        $mime = strtolower(trim((string) $file_mime));
        $ext = '';
        $dot_pos = strrpos($name, '.');
        if ($dot_pos !== false && $dot_pos < (strlen($name) - 1)) {
            $ext = substr($name, $dot_pos);
        }

        foreach ($tokens as $token_raw) {
            $token = strtolower(trim((string) $token_raw));
            if ($token === '') {
                continue;
            }

            if (strpos($token, '.') === 0) {
                if ($ext !== '' && $ext === $token) {
                    return true;
                }
                continue;
            }

            if (substr($token, -2) === '/*') {
                $prefix = substr($token, 0, -1);
                if ($mime !== '' && strpos($mime, $prefix) === 0) {
                    return true;
                }
                continue;
            }

            if ($mime !== '' && $mime === $token) {
                return true;
            }
        }

        return false;
    }
}

/** AJAX: afb_attach_file (single file packet) */
function afb_api_attach_file() {
$request_id = sanitize_text_field($_POST['request_id'] ?? '');
$task_gid   = sanitize_text_field($_POST['task_gid'] ?? '');
if (!$request_id || !$task_gid) wp_send_json_error(['message'=>'Missing params']);

// Load PAT server-side and ensure task_gid matches the canonical one for this request
$secret = afb_secret_get($request_id);
$pat    = (string)($secret['pat'] ?? '');
if ($pat === '') {
    wp_send_json_error(['message' => 'Auth not initialised for this request.']);
}
if (!empty($secret['task_gid']) && $secret['task_gid'] !== $task_gid) {
    wp_send_json_error(['message' => 'task_gid does not match request_id']);
}

$private_task_gid = sanitize_text_field((string) ($secret['private_task_gid'] ?? ''));
if (!ctype_digit($private_task_gid)) {
    $private_task_gid = '';
}
$private_companion_upload_mode = sanitize_text_field((string) ($secret['private_companion_upload_mode'] ?? 'main_only'));
if (!in_array($private_companion_upload_mode, ['main_only', 'copy_to_companion', 'companion_only'], true)) {
    $private_companion_upload_mode = 'main_only';
}
$private_companion_upload_modes_by_field = [];
if (!empty($secret['private_companion_upload_modes_by_field']) && is_array($secret['private_companion_upload_modes_by_field'])) {
    foreach ($secret['private_companion_upload_modes_by_field'] as $upload_id_raw => $upload_mode_raw) {
        $upload_id = sanitize_text_field((string) $upload_id_raw);
        if ($upload_id === '' || strpos($upload_id, 'upload_') !== 0) {
            continue;
        }

        $upload_mode = sanitize_text_field((string) $upload_mode_raw);
        if (!in_array($upload_mode, ['main_only', 'copy_to_companion', 'companion_only'], true)) {
            continue;
        }

        $private_companion_upload_modes_by_field[$upload_id] = $upload_mode;
    }
}
$upload_accept_types_by_field = [];
if (!empty($secret['upload_accept_types_by_field']) && is_array($secret['upload_accept_types_by_field'])) {
    foreach ($secret['upload_accept_types_by_field'] as $upload_id_raw => $upload_accept_raw) {
        $upload_id = sanitize_text_field((string) $upload_id_raw);
        if ($upload_id === '' || strpos($upload_id, 'upload_') !== 0) {
            continue;
        }

        $accept_tokens = afb_normalize_upload_accept_tokens_from_csv($upload_accept_raw);
        if (empty($accept_tokens)) {
            continue;
        }

        $upload_accept_types_by_field[$upload_id] = implode(',', $accept_tokens);
    }
}
$upload_max_file_mb_by_field = [];
if (!empty($secret['upload_max_file_mb_by_field']) && is_array($secret['upload_max_file_mb_by_field'])) {
    foreach ($secret['upload_max_file_mb_by_field'] as $upload_id_raw => $max_file_mb_raw) {
        $upload_id = sanitize_text_field((string) $upload_id_raw);
        if ($upload_id === '' || strpos($upload_id, 'upload_') !== 0) {
            continue;
        }

        $max_file_mb = (float) $max_file_mb_raw;
        if ($max_file_mb <= 0) {
            continue;
        }

        $upload_max_file_mb_by_field[$upload_id] = min(512, round($max_file_mb, 2));
    }
}


    if (empty($_FILES['file']['tmp_name'])) wp_send_json_error(['message'=>'No file']);

    $tmp = $_FILES['file']['tmp_name'];
    $name= sanitize_file_name($_FILES['file']['name']);
    $mime= mime_content_type($tmp) ?: 'application/octet-stream';
    if (function_exists('wp_check_filetype_and_ext')) {
        $checked_type = wp_check_filetype_and_ext($tmp, $name);
        $wp_type = sanitize_text_field((string) ($checked_type['type'] ?? ''));
        if (($mime === '' || $mime === 'application/octet-stream') && $wp_type !== '') {
            $mime = $wp_type;
        }
    }
    $client_sig = sanitize_text_field($_POST['upload_sig'] ?? '');
    $upload_field_id = sanitize_text_field($_POST['upload_field_id'] ?? '');
    $size = @filesize($tmp);
    if (!is_int($size) || $size < 0) {
        $size = 0;
    }

    $resolved_max_file_mb = 0.0;
    if ($upload_field_id !== '' && !empty($upload_max_file_mb_by_field[$upload_field_id])) {
        $resolved_max_file_mb = max(0.0, (float) $upload_max_file_mb_by_field[$upload_field_id]);
    }
    $resolved_max_file_bytes = $resolved_max_file_mb > 0
        ? (int) round($resolved_max_file_mb * 1024 * 1024)
        : 0;

    $resolved_upload_mode = $private_companion_upload_mode;
    if ($upload_field_id !== '' && !empty($private_companion_upload_modes_by_field[$upload_field_id])) {
        $resolved_upload_mode = $private_companion_upload_modes_by_field[$upload_field_id];
    }
    if (!in_array($resolved_upload_mode, ['main_only', 'copy_to_companion', 'companion_only'], true)) {
        $resolved_upload_mode = 'main_only';
    }

    $resolved_upload_accept_tokens = [];
    if ($upload_field_id !== '' && !empty($upload_accept_types_by_field[$upload_field_id])) {
        $resolved_upload_accept_tokens = afb_normalize_upload_accept_tokens_from_csv($upload_accept_types_by_field[$upload_field_id]);
    }

    $target_task_gids = [];
    if ($resolved_upload_mode === 'companion_only') {
        if ($private_task_gid !== '' && $private_task_gid !== $task_gid) {
            $target_task_gids[] = $private_task_gid;
        }
    } elseif ($resolved_upload_mode === 'copy_to_companion') {
        $target_task_gids[] = $task_gid;
        if ($private_task_gid !== '' && $private_task_gid !== $task_gid) {
            $target_task_gids[] = $private_task_gid;
        }
    } else {
        $target_task_gids[] = $task_gid;
    }

    $target_task_gids = array_values(array_unique(array_filter($target_task_gids, static function ($gid) {
        return is_string($gid) && $gid !== '';
    })));

    if ($resolved_max_file_bytes > 0 && $size > $resolved_max_file_bytes) {
        $max_file_label = rtrim(rtrim(number_format($resolved_max_file_mb, 2, '.', ''), '0'), '.');
        $fail_message = 'File is too large for this upload field. Max allowed: ' . $max_file_label . ' MB per file.';

        if (function_exists('afb_log')) {
            afb_log(
                '[attach-file] blocked size request=' . $request_id .
                ' field=' . $upload_field_id .
                ' file=' . $name .
                ' size=' . $size .
                ' max_bytes=' . $resolved_max_file_bytes,
                'afb-debug.log'
            );
        }

        $st = afb_status_get($request_id);
        $failed = $st['uploads']['failed'];
        $failed[] = ['name' => $name, 'msg' => $fail_message];
        afb_status_merge($request_id, [
            'uploads' => [
                'total' => $st['uploads']['total'],
                'done' => (int) $st['uploads']['done'],
                'failed' => $failed,
            ],
        ]);

        wp_send_json_success([
            'ok' => false,
            'http_code' => 413,
            'route' => $resolved_upload_mode,
            'targets' => $target_task_gids,
            'failed_targets' => [],
            'message' => $fail_message,
            'max_file_mb' => $max_file_label,
        ]);
    }

    if (!empty($resolved_upload_accept_tokens) && !afb_file_matches_upload_accept_tokens($name, $mime, $resolved_upload_accept_tokens)) {
        $allowed_types_label = implode(', ', $resolved_upload_accept_tokens);
        $fail_message = $allowed_types_label !== ''
            ? 'File type is not allowed for this upload field. Allowed: ' . $allowed_types_label
            : 'File type is not allowed for this upload field.';

        if (function_exists('afb_log')) {
            afb_log(
                '[attach-file] blocked type request=' . $request_id .
                ' field=' . $upload_field_id .
                ' file=' . $name .
                ' mime=' . $mime .
                ' allowed=' . $allowed_types_label,
                'afb-debug.log'
            );
        }

        $st = afb_status_get($request_id);
        $failed = $st['uploads']['failed'];
        $failed[] = ['name' => $name, 'msg' => $fail_message];
        afb_status_merge($request_id, [
            'uploads' => [
                'total' => $st['uploads']['total'],
                'done' => (int) $st['uploads']['done'],
                'failed' => $failed,
            ],
        ]);

        wp_send_json_success([
            'ok' => false,
            'http_code' => 415,
            'route' => $resolved_upload_mode,
            'targets' => $target_task_gids,
            'failed_targets' => [],
            'message' => $fail_message,
        ]);
    }

    // Make packet uploads idempotent per request/task to avoid duplicate attachments
    // when the same browser packet is retried.
    $sig = '';
    if ($client_sig !== '') {
        $sig = 'client:' . $client_sig;
    } elseif (is_string($tmp) && $tmp !== '' && @is_file($tmp) && @is_readable($tmp)) {
        $hash = @sha1_file($tmp);
        if (is_string($hash) && $hash !== '') {
            $sig = 'sha1:' . $hash . '|' . $name . '|' . (string) (is_int($size) ? $size : -1);
        }
    }

    if ($sig === '') {
        // Last-resort fallback when file hashing cannot be read.
        $sig = 'meta:' . $name . '|' . (string) (is_int($size) ? $size : -1) . '|' . $mime . '|' . $upload_field_id;
    }

    $seen_upload_sigs = [];
    if (!empty($secret['upload_sigs']) && is_array($secret['upload_sigs'])) {
        $seen_upload_sigs = $secret['upload_sigs'];
    }

    $target_sig_keys = [];
    foreach ($target_task_gids as $target_task_gid) {
        $target_sig_keys[$target_task_gid] = 'task:' . $target_task_gid . '|' . $sig;
    }

    $all_targets_already_done = !empty($target_sig_keys);
    foreach ($target_sig_keys as $target_sig_key) {
        if (($seen_upload_sigs[$target_sig_key] ?? '') !== 'done') {
            $all_targets_already_done = false;
            break;
        }
    }

    if ($all_targets_already_done) {
        if (function_exists('afb_log')) {
            afb_log(
                '[attach-file] skip duplicate request=' . $request_id .
                ' route=' . $resolved_upload_mode .
                ' targets=' . implode(',', $target_task_gids) .
                ' file=' . $name .
                ' sig=' . substr($sig, 0, 120),
                'afb-debug.log'
            );
        }
        wp_send_json_success(['ok' => true, 'duplicate' => true, 'sig' => $sig, 'route' => $resolved_upload_mode, 'targets' => $target_task_gids]);
    }

    // Reserve per-target signatures before network calls so concurrent retries
    // cannot upload the same packet to the same destination twice.
    foreach ($target_sig_keys as $target_sig_key) {
        if (($seen_upload_sigs[$target_sig_key] ?? '') !== 'done') {
            $seen_upload_sigs[$target_sig_key] = 'pending';
        }
    }
    afb_secret_set($request_id, ['upload_sigs' => $seen_upload_sigs]);

    $http_codes = [];
    $failed_targets = [];
    $missing_companion_target = false;
    if (empty($target_task_gids)) {
        $missing_companion_target = true;
    } else {
        foreach ($target_task_gids as $target_task_gid) {
            $target_sig_key = $target_sig_keys[$target_task_gid] ?? '';
            if ($target_sig_key === '') {
                continue;
            }
            if (($seen_upload_sigs[$target_sig_key] ?? '') === 'done') {
                continue;
            }

            $r = afb_asana_request('POST', "https://app.asana.com/api/1.0/tasks/$target_task_gid/attachments", $pat, [
                'fields' => ['file' => new CURLFile($tmp, $mime, $name)]
            ], 0);

            $http_code = (int) ($r['code'] ?? 0);
            $http_codes[$target_task_gid] = $http_code;
            if (in_array($http_code, [200, 201], true)) {
                $seen_upload_sigs[$target_sig_key] = 'done';
            } else {
                unset($seen_upload_sigs[$target_sig_key]);
                $failed_targets[] = [
                    'task_gid' => $target_task_gid,
                    'http_code' => $http_code,
                ];
            }
        }
    }

    afb_secret_set($request_id, ['upload_sigs' => $seen_upload_sigs]);

    $ok = !$missing_companion_target && empty($failed_targets);
    $http_code = 0;
    if (!empty($http_codes)) {
        $http_code = max(array_values($http_codes));
    }
    if ($missing_companion_target) {
        $http_code = 409;
    }

    if (function_exists('afb_log')) {
        $http_bits = [];
        foreach ($http_codes as $target_task_gid => $target_http) {
            $http_bits[] = $target_task_gid . ':' . $target_http;
        }
        afb_log(
            '[attach-file] request=' . $request_id .
            ' route=' . $resolved_upload_mode .
            ' source_task=' . $task_gid .
            ' targets=' . implode(',', $target_task_gids) .
            ' file=' . $name .
            ' size=' . (string) (is_int($size) ? $size : -1) .
            ' field=' . $upload_field_id .
            ' http=' . implode(',', $http_bits) .
            ' ok=' . ($ok ? '1' : '0') .
            ' sig=' . substr($sig, 0, 120),
            'afb-debug.log'
        );
    }

    $st = afb_status_get($request_id);
    $done = (int)$st['uploads']['done'] + ($ok ? 1 : 0);
    $failed = $st['uploads']['failed'];
    if (!$ok) {
        $fail_message = '';
        if ($missing_companion_target) {
            $fail_message = 'Companion upload routing is enabled, but no companion task is available for this request.';
        } elseif (!empty($failed_targets)) {
            $target_messages = [];
            foreach ($failed_targets as $failed_target) {
                $target_messages[] = $failed_target['task_gid'] . ' (HTTP ' . (int) $failed_target['http_code'] . ')';
            }
            $fail_message = 'Upload failed for destination task(s): ' . implode(', ', $target_messages);
        } else {
            $fail_message = 'Upload failed.';
        }

        $failed[] = ['name' => $name, 'msg' => $fail_message];
    }

    afb_status_merge($request_id, ['uploads'=>['total'=>$st['uploads']['total'],'done'=>$done,'failed'=>$failed]]);
    wp_send_json_success([
        'ok' => $ok,
        'http_code' => $http_code,
        'route' => $resolved_upload_mode,
        'targets' => $target_task_gids,
        'failed_targets' => $failed_targets,
    ]);
}
