<?php
// includes/functions/resolvers/user-resolver.php
if (!defined('ABSPATH')) exit;

require_once AFB_PLUGIN_DIR . 'includes/lib/asana-client.php';

/* ─────────────────────────────────────────────────────────────
 * Helpers (sanitise, cache)
 * ──────────────────────────────────────────────────────────── */
if (!function_exists('afb_norm_email')) {
    function afb_norm_email($email){ return strtolower(trim((string)$email)); }
}
if (!function_exists('afb_cache_get')) {
    function afb_cache_get($key){ return function_exists('get_transient') ? get_transient($key) : false; }
}
if (!function_exists('afb_cache_set')) {
    function afb_cache_set($key,$value,$ttl=3600){ if (function_exists('set_transient')) set_transient($key,$value,$ttl); }
}
if (!function_exists('afb_msleep')) {
    function afb_msleep($ms){ usleep(max(0,(int)$ms)*1000); }
}

/* ─────────────────────────────────────────────────────────────
 * Project → Workspace
 * ──────────────────────────────────────────────────────────── */
if (!function_exists('afb_project_workspace_gid')) {
    function afb_project_workspace_gid($project_gid, $pat) {
        if (!$project_gid || !$pat) return '';
        $r = afb_asana_request('GET',
            "https://app.asana.com/api/1.0/projects/{$project_gid}?opt_fields=workspace.gid",
            (string)$pat
        );
        if (($r['code'] ?? 0) !== 200) return '';
        $jd = json_decode($r['body'] ?? '', true);
        return (string)($jd['data']['workspace']['gid'] ?? '');
    }
}

/* ─────────────────────────────────────────────────────────────
 * Email extraction (robust; keeps your behaviour)
 * ──────────────────────────────────────────────────────────── */
if (!function_exists('afb_extract_emails_from_mixed')) {
    function afb_extract_emails_from_mixed($v){
        $out=[]; $push=function($s)use(&$out){
            $s=(string)$s; if($s==='')return;
            if(preg_match_all('/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+\.[A-Z]{2,}/i',$s,$m)){
                foreach($m[0] as $e){ $out[]=strtolower($e); }
            }
        };
        if (is_array($v)) array_walk_recursive($v,function($vv)use($push){$push($vv);});
        else $push($v);
        return array_values(array_unique($out));
    }
}
if (!function_exists('afb_guess_submitter_email_from_post')) {
    function afb_guess_submitter_email_from_post($post){
        $keys=['email','client_email','requester_email','customer_email','contact_email','submitted_email','your_email','work_email','user_email','submitter_email'];
        foreach ($keys as $k){
            if (!empty($post[$k]) && filter_var($post[$k], FILTER_VALIDATE_EMAIL)) {
                return apply_filters('afb/submitter_email', trim($post[$k]), $post);
            }
        }
        foreach ($post as $k=>$v){
            if (is_string($v) && stripos($k,'email')!==false && filter_var($v, FILTER_VALIDATE_EMAIL)) {
                return apply_filters('afb/submitter_email', trim($v), $post);
            }
        }
        if (!empty($post['custom_fields'])){
            $emails = afb_extract_emails_from_mixed($post['custom_fields']);
            if (!empty($emails[0])) return apply_filters('afb/submitter_email',$emails[0],$post);
        }
        $emails = afb_extract_emails_from_mixed($post);
        if (!empty($emails[0])) return apply_filters('afb/submitter_email',$emails[0],$post);
        return apply_filters('afb/submitter_email','',$post);
    }
}

/* ─────────────────────────────────────────────────────────────
 * User lookups (prefer direct endpoint; fallbacks retained)
 * ──────────────────────────────────────────────────────────── */

/** Fast + exact: GET /users?workspace=WS&email=E  → first match or null */
if (!function_exists('afb_lookup_asana_user_by_email')) {
    function afb_lookup_asana_user_by_email($workspace_gid, $email, $pat){
        $email = afb_norm_email($email);
        if (!$workspace_gid || !$email || !$pat) return null;

        $url = 'https://app.asana.com/api/1.0/users'
             . '?workspace=' . rawurlencode($workspace_gid)
             . '&email='     . rawurlencode($email);

        $r = afb_asana_request('GET', $url, (string)$pat);
        if (($r['code'] ?? 0) !== 200) return null;

        $jd  = json_decode($r['body'] ?? '', true);
        $arr = $jd['data'] ?? [];
        if (is_array($arr) && !empty($arr[0]['gid'])) {
            $u = $arr[0];
            return ['gid'=>(string)$u['gid'], 'name'=>(string)($u['name']??''), 'email'=>$email];
        }
        return null;
    }
}

/** Fallback: typeahead (partial) → then filter exact email */
if (!function_exists('afb_typeahead_user_by_email')) {
    function afb_typeahead_user_by_email($workspace_gid, $email, $pat){
        $email = afb_norm_email($email);
        if (!$workspace_gid || !$email) return null;

        $r = afb_asana_request('GET',
            "https://app.asana.com/api/1.0/workspaces/{$workspace_gid}/typeahead?type=user&limit=10&query=" . rawurlencode($email) . "&opt_fields=name,email,resource_type",
            (string)$pat
        );
        if (($r['code'] ?? 0) !== 200) return null;
        $jd = json_decode($r['body'] ?? '', true);
        foreach ((array)($jd['data'] ?? []) as $row) {
            if (($row['resource_type'] ?? '') !== 'user') continue;
            if (!empty($row['email']) && afb_norm_email($row['email']) === $email) {
                return ['gid'=>(string)$row['gid'],'name'=>(string)($row['name']??''),'email'=>$email];
            }
        }
        return null;
    }
}

/** Fallback: list & scan users (paged) for exact email */
if (!function_exists('afb_list_users_exact_email')) {
    function afb_list_users_exact_email($workspace_gid, $email, $pat){
        $email = afb_norm_email($email);
        if (!$workspace_gid || !$email) return null;

        $endpoints = [
            "https://app.asana.com/api/1.0/users?workspace={$workspace_gid}&limit=100&opt_fields=name,email",
            "https://app.asana.com/api/1.0/workspaces/{$workspace_gid}/users?limit=100&opt_fields=name,email",
        ];
        foreach ($endpoints as $base) {
            $next = $base;
            for ($i=0; $i<8 && $next; $i++){
                $r = afb_asana_request('GET', $next, (string)$pat);
                if (($r['code'] ?? 0) !== 200) break;
                $jd = json_decode($r['body'] ?? '', true);
                foreach ((array)($jd['data'] ?? []) as $u) {
                    if (!empty($u['email']) && afb_norm_email($u['email']) === $email) {
                        return ['gid'=>(string)$u['gid'],'name'=>(string)($u['name']??''),'email'=>$email];
                    }
                }
                $next = $jd['next_page']['uri'] ?? null;
            }
        }
        return null;
    }
}

/** Cached: find user by email in a specific workspace (direct → typeahead → list) */
if (!function_exists('afb_find_asana_user_by_email')) {
    function afb_find_asana_user_by_email($email, $workspace_gid, $pat){
        $email = afb_norm_email($email);
        if ($email === '' || !$workspace_gid) return null;

        $ckey = 'afb_user_by_email_' . md5($workspace_gid.'|'.$email);
        $cached = afb_cache_get($ckey);
        if ($cached !== false) return $cached;

        $hit = afb_lookup_asana_user_by_email($workspace_gid, $email, $pat);
        if (!$hit) $hit = afb_typeahead_user_by_email($workspace_gid, $email, $pat);
        if (!$hit) $hit = afb_list_users_exact_email($workspace_gid, $email, $pat);

        afb_cache_set($ckey, $hit ?: null, $hit ? 12*HOUR_IN_SECONDS : 2*MINUTE_IN_SECONDS);
        return $hit;
    }
}

/* ─────────────────────────────────────────────────────────────
 * Cross-workspace “exists anywhere?” + invite-to-workspace
 * ──────────────────────────────────────────────────────────── */
if (!function_exists('afb_list_workspaces')) {
    function afb_list_workspaces($pat){
        $r = afb_asana_request('GET', "https://app.asana.com/api/1.0/workspaces?limit=100&opt_fields=name", (string)$pat);
        if (($r['code'] ?? 0) !== 200) return [];
        $jd = json_decode($r['body'] ?? '', true);
        $out=[];
        foreach ((array)($jd['data'] ?? []) as $ws) if (!empty($ws['gid'])) $out[]=(string)$ws['gid'];
        return $out;
    }
}

/**
 * Look up email across all configured PATs + workspaces you can see.
 * Returns ['hit'=>user,'workspace_gid'=>..., 'account_id'=>...] or null.
 */
if (!function_exists('afb_find_asana_user_anywhere')) {
    function afb_find_asana_user_anywhere($email){
        global $wpdb;
        $email = afb_norm_email($email);
        if ($email === '') return null;

        $ckey   = 'afb_any_user_' . md5($email);
        $cached = afb_cache_get($ckey);
        if ($cached !== false) return $cached ?: null;

        $acct_tbl = $wpdb->prefix . 'asana_accounts';
        $accounts = (array)$wpdb->get_results("SELECT id,pat FROM {$acct_tbl} WHERE active=1 ORDER BY id DESC", ARRAY_A);
        if (!$accounts) $accounts = (array)$wpdb->get_results("SELECT id,pat FROM {$acct_tbl} ORDER BY id DESC", ARRAY_A);

        foreach ($accounts as $acc){
            $token = function_exists('afb_decrypt') ? afb_decrypt($acc['pat']) : $acc['pat'];
            if (!$token) continue;

            foreach (afb_list_workspaces($token) as $ws_gid){
                $hit = afb_lookup_asana_user_by_email($ws_gid, $email, $token);
                if (!$hit) $hit = afb_typeahead_user_by_email($ws_gid, $email, $token);
                if (!$hit) $hit = afb_list_users_exact_email($ws_gid, $email, $token);
                if ($hit){
                    $res = ['hit'=>$hit, 'workspace_gid'=>$ws_gid, 'account_id'=>(int)$acc['id']];
                    afb_cache_set($ckey, $res, 12*HOUR_IN_SECONDS);
                    return $res;
                }
            }
        }
        afb_cache_set($ckey, null, 2*MINUTE_IN_SECONDS);
        return null;
    }
}

/** Invite user (email) to a workspace; PAT must have permission. */
if (!function_exists('afb_invite_user_to_workspace')) {
    function afb_invite_user_to_workspace($workspace_gid, $email, $pat){
        $payload = ['data'=>['user'=>(string)$email]];
        $r = afb_asana_request('POST', "https://app.asana.com/api/1.0/workspaces/{$workspace_gid}/addUser", (string)$pat, ['json'=>$payload], 1);
        $code = (int)($r['code'] ?? 0);
        return in_array($code, [200,201], true);
    }
}

/* ─────────────────────────────────────────────────────────────
 * Collaborator gate (exists anywhere → invite if needed → add)
 * ──────────────────────────────────────────────────────────── */
/**
 * Mutates $payload by reference to add followers[] only when the submitter:
 *  1) Exists in Asana (any workspace you can see), and
 *  2) Is or becomes a member of the project’s workspace (invite if necessary).
 */
if (!function_exists('afb_apply_collaborator_email_gate')) {
    function afb_apply_collaborator_email_gate(&$payload, $project_gid, $pat, $post){
        // Normalise payload shape
        $path =& $payload;
        if (isset($payload['data']) && is_array($payload['data'])) $path =& $payload['data'];

        // Get submitter email
        $submitter_email = sanitize_email($post['submitter_email'] ?? '') ?: afb_guess_submitter_email_from_post($post);
        if (!$submitter_email) return;

        // A) Does this email exist anywhere?
        $any = afb_find_asana_user_anywhere($submitter_email);
        if (!$any){
            if (function_exists('afb_log')) afb_log("collab_gate:any: {$submitter_email} not found anywhere → skip",'asana_collab_gate');
            return;
        }

        // B) Ensure they’re in THIS project’s workspace
        $project_ws = afb_project_workspace_gid($project_gid, $pat);
        if (!$project_ws) return;

        $hit_here = afb_find_asana_user_by_email($submitter_email, $project_ws, $pat);

        // If not present, try inviting (PAT must be allowed)
        if (!$hit_here){
            $invited = afb_invite_user_to_workspace($project_ws, $submitter_email, $pat);
            if ($invited){
                // brief backoff to allow directory update
                for ($i=0; $i<4; $i++){
                    afb_msleep(250*(1+$i)); // 250ms, 500ms, 750ms, 1000ms
                    $hit_here = afb_find_asana_user_by_email($submitter_email, $project_ws, $pat);
                    if ($hit_here) break;
                }
            }
            if (!$hit_here){
                if (function_exists('afb_log')) {
                    afb_log([
                        'msg'        => 'collab_gate:any: user exists elsewhere; invite '.(($invited??false)?'sent':'skipped').' but not yet in project workspace',
                        'email'      => $submitter_email,
                        'project_ws' => $project_ws
                    ], 'asana_collab_gate');
                }
                return;
            }
        }

        // C) Add follower GID (de-dupe)
        $gid = (string)$hit_here['gid'];
        $followers = isset($path['followers']) && is_array($path['followers']) ? $path['followers'] : [];
        $followers[] = $gid;
        // keep only numeric GIDs
        $path['followers'] = array_values(array_unique(array_filter($followers, fn($v)=>is_string($v)&&preg_match('/^\d{6,}$/',$v))));

        if (function_exists('afb_log')) afb_log("collab_gate:any: added follower {$gid} for {$submitter_email}", 'asana_collab_gate');
    }
}
