<?php
declare(strict_types=1);

require_once __DIR__ . '/../auth.php';

// APIは302禁止：未ログインは401 JSON
require_login_json();

$userId = (int)($_SESSION['user_id'] ?? 0);
if ($userId <= 0) {
    json_exit(401, ['ok'=>false,'error'=>'UNAUTHORIZED']);
}

// CSRF（セッション側のキー名揺れを吸収）
$postedToken = (string)($_POST['csrf_token'] ?? '');
$sessionCandidates = ['csrf_token', 'csrf', '_csrf', 'csrfToken', 'token'];
$sessionToken = '';
foreach ($sessionCandidates as $k) {
    if (!empty($_SESSION[$k]) && is_string($_SESSION[$k])) {
        $sessionToken = $_SESSION[$k];
        break;
    }
}
if ($sessionToken !== '') {
    if ($postedToken === '' || !hash_equals($sessionToken, $postedToken)) {
        json_exit(400, [
            'ok' => false,
            'error' => '不正なリクエストです（CSRF）',
            'code' => 'CSRF',
        ]);
    }
}
// ※セッション側にCSRFキーが無い場合はここではブロックしない（既存実装差異吸収）

// 入力
// UIは company_id で送ってくるが、DBは customer_id(FK) が必須
$customerId  = (int)($_POST['customer_id'] ?? ($_POST['company_id'] ?? 0));
$taskTitle   = trim((string)($_POST['task_title'] ?? ''));
$taskDetail  = trim((string)($_POST['task_detail'] ?? ''));
$dueDateRaw  = trim((string)($_POST['due_date'] ?? ''));

$assignees = $_POST['assignees'] ?? $_POST['assignees_'] ?? null;
if ($assignees === null) $assignees = $_POST['assignees'] ?? null;
if (!is_array($assignees)) {
    // name="assignees[]" なので通常は配列。念のため単体も吸収
    $assignees = isset($_POST['assignees']) ? [(string)$_POST['assignees']] : [];
}
$assigneeIds = array_values(array_unique(array_filter(array_map(static function($v){
    $n = (int)$v;
    return $n > 0 ? $n : 0;
}, $assignees))));

if ($customerId <= 0) {
    json_exit(400, ['ok'=>false,'error'=>'顧客が未選択です','code'=>'VALIDATION']);
}

  if ($taskTitle === '') {
      json_exit(400, ['ok'=>false,'error'=>'タイトルを入力してください','code'=>'VALIDATION']);
  }
  if (count($assigneeIds) < 1) {
      json_exit(400, ['ok'=>false,'error'=>'担当者を1名以上選択してください','code'=>'VALIDATION']);
  }

// due_date を YYYY-MM-DD だけ許可（空はNULL）
$dueDate = null;
if ($dueDateRaw !== '') {
    if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $dueDateRaw)) {
        json_exit(400, ['ok'=>false,'error'=>'VALIDATION','message'=>'期限の形式が不正です']);
    }
    $dueDate = $dueDateRaw;
}

try {
    $pdo = db();
    $pdo->beginTransaction();

    // --- tasks テーブル列取得 ---
    $stCols = $pdo->prepare("
        SELECT COLUMN_NAME
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_SCHEMA = DATABASE()
          AND TABLE_NAME = 'tasks'
    ");
    $stCols->execute();
    $taskCols = array_map('strval', $stCols->fetchAll(PDO::FETCH_COLUMN));
    if (!$taskCols) {
        throw new RuntimeException("tasks テーブルが見つかりません");
    }

    // ? task_uid（UNIQUE）対策：存在するなら必ずINSERT時に値を入れる
    $colTaskUid = in_array('task_uid', $taskCols, true) ? 'task_uid' : null;
    $colTaskUid = in_array('task_uid', $taskCols, true) ? 'task_uid' : null;


    // 列名候補（実DB差異吸収）
    // DBは customer_id が外部キーで必須（fk_tasks_customer）
    $colCompany = in_array('customer_id', $taskCols, true) ? 'customer_id' : null;
    if (!$colCompany) {
        throw new RuntimeException("tasks.customer_id が存在しません（FK必須）");
    }

    $colTitle = null;
    foreach (['task_title','title','subject'] as $c) {
        if (in_array($c, $taskCols, true)) { $colTitle = $c; break; }
    }
    $colDetail = null;
    foreach (['task_detail','body','detail','description'] as $c) {
        if (in_array($c, $taskCols, true)) { $colDetail = $c; break; }
    }
    $colDue = null;
    foreach (['due_date','deadline','due'] as $c) {
        if (in_array($c, $taskCols, true)) { $colDue = $c; break; }
    }
    $colStatus = in_array('status', $taskCols, true) ? 'status' : null;

$colAssigneeUserIds = in_array('assignee_user_ids', $taskCols, true) ? 'assignee_user_ids' : null;

// 互換：単一担当カラムがあるなら先頭も入れる（任意だが将来の拡張に強い）
$colAssignType = in_array('assign_type', $taskCols, true) ? 'assign_type' : null;
$colAssigneeUserId = in_array('assignee_user_id', $taskCols, true) ? 'assignee_user_id' : null;


    // created_by（無ければ無視）
    $colCreatedBy = null;
    foreach (['created_by','created_user_id','creator_user_id','created_by_user_id'] as $c) {
        if (in_array($c, $taskCols, true)) { $colCreatedBy = $c; break; }
    }

    // created_at / updated_at（無ければ無視）
    $colCreatedAt = in_array('created_at', $taskCols, true) ? 'created_at' : null;
    $colUpdatedAt = in_array('updated_at', $taskCols, true) ? 'updated_at' : null;

    if (!$colCompany || !$colTitle) {
        throw new RuntimeException("tasks テーブルの必須列が不足しています（company_id系 / title系）");
    }

    // INSERT組み立て
    $fields = [];
    $placeholders = [];
    $params = [];

    $fields[] = $colCompany; $placeholders[] = '?'; $params[] = $customerId;
    $fields[] = $colTitle;   $placeholders[] = '?'; $params[] = $taskTitle;

    if ($colDetail) {
        $fields[] = $colDetail; $placeholders[] = '?'; $params[] = $taskDetail;
    }
    if ($colDue) {
        $fields[] = $colDue; $placeholders[] = '?'; $params[] = $dueDate; // null可
    }
    if ($colStatus) {
        // board.php の statusChip が todo/doing/returned/done を期待
        $fields[] = $colStatus; $placeholders[] = '?'; $params[] = 'todo';
    }

if ($colAssigneeUserIds) {
    $fields[] = $colAssigneeUserIds;
    $placeholders[] = '?';
    $params[] = json_encode($assigneeIds, JSON_UNESCAPED_UNICODE);
}

// 互換（単一担当の列がある場合）
if ($colAssignType && $colAssigneeUserId && count($assigneeIds) >= 1) {
    $fields[] = $colAssignType;       $placeholders[] = '?'; $params[] = 'user';
    $fields[] = $colAssigneeUserId;   $placeholders[] = '?'; $params[] = (int)$assigneeIds[0];
}


    // ? task_uid（UNIQUE）対策：空文字''が入ると重複するので必ず一意値を入れる
    if ($colTaskUid) {
        $uid = bin2hex(random_bytes(16)); // 32文字・衝突しにくい
        $fields[] = $colTaskUid; $placeholders[] = '?'; $params[] = $uid;
    }

    if ($colCreatedBy) {
        $fields[] = $colCreatedBy; $placeholders[] = '?'; $params[] = (int)$userId;
    }
    if ($colCreatedAt) {
        $fields[] = $colCreatedAt; $placeholders[] = 'NOW()';
    }
    if ($colUpdatedAt) {
        $fields[] = $colUpdatedAt; $placeholders[] = 'NOW()';
    }

    // NOW() はプレースホルダにしない
    $colsSql = implode(',', array_map(static fn($x)=>"`$x`", $fields));
    $valsSql = implode(',', array_map(static function($x){
        return $x === 'NOW()' ? 'NOW()' : '?';
    }, $placeholders));

    $sql = "INSERT INTO tasks ($colsSql) VALUES ($valsSql)";
    $st = $pdo->prepare($sql);

    // NOW()を含む場合、params数と?数がズレるので、?の数だけbindする
    $bind = [];
    foreach ($placeholders as $i => $ph) {
        if ($ph === 'NOW()') continue;
        $bind[] = $params[count($bind)];
    }
    $st->execute($bind);

    $taskId = (int)$pdo->lastInsertId();
    if ($taskId <= 0) throw new RuntimeException("タスクID取得に失敗しました");

    // --- 担当者リンクテーブルを探して入れる（存在すれば） ---
    // 候補：task_assignees / tasks_assignees / task_assignments / task_users
    $candidateLinkTables = ['task_assignees','tasks_assignees','task_assignments','task_users','task_assignee'];
    $linkTable = null;

    $stTbl = $pdo->prepare("
        SELECT TABLE_NAME
        FROM INFORMATION_SCHEMA.TABLES
        WHERE TABLE_SCHEMA = DATABASE()
          AND TABLE_NAME = ?
        LIMIT 1
    ");
    foreach ($candidateLinkTables as $t) {
        $stTbl->execute([$t]);
        if ($stTbl->fetchColumn()) { $linkTable = $t; break; }
    }

    if ($linkTable) {
        // リンク列を推測
        $stLinkCols = $pdo->prepare("
            SELECT COLUMN_NAME
            FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_SCHEMA = DATABASE()
              AND TABLE_NAME = ?
        ");
        $stLinkCols->execute([$linkTable]);
        $linkCols = array_map('strval', $stLinkCols->fetchAll(PDO::FETCH_COLUMN));

        $colTaskId = null;
        foreach (['task_id','tasks_id'] as $c) {
            if (in_array($c, $linkCols, true)) { $colTaskId = $c; break; }
        }
        $colUserId = null;
        foreach (['user_id','assignee_user_id','staff_id'] as $c) {
            if (in_array($c, $linkCols, true)) { $colUserId = $c; break; }
        }

        if ($colTaskId && $colUserId) {
            $ins = $pdo->prepare("INSERT INTO `$linkTable` (`$colTaskId`,`$colUserId`) VALUES (?,?)");
            foreach ($assigneeIds as $aid) {
                $ins->execute([$taskId, (int)$aid]);
            }
        }
        // 列推測できなければ無視（落とさない）
    }

    $pdo->commit();
    // --- Push通知（失敗してもタスク作成自体は成功扱い） ---
error_log('[push] attempt task_id='.(int)$taskId.' assignees='.json_encode($assigneeIds));
    // --- Push通知（DB確定後の担当者を正とする。失敗してもタスク作成自体は成功） ---
    try {
        // DBから確定済み担当者IDを再取得（tasks.assignee_user_ids を正とする）
        $assigneeIdsDb = [];
        try {
            $stA = $pdo->prepare("SELECT assignee_user_ids FROM tasks WHERE id=?");
            $stA->execute([(int)$taskId]);
            $raw = (string)($stA->fetchColumn() ?: '');
            $decoded = json_decode($raw, true);
            if (is_array($decoded)) {
                foreach ($decoded as $v) {
                    $n = (int)$v;
                    if ($n > 0) $assigneeIdsDb[] = $n;
                }
                $assigneeIdsDb = array_values(array_unique($assigneeIdsDb));
            }
        } catch (Throwable $e) {
            $assigneeIdsDb = [];
        }

        // 顧客名を取得（customers.name 前提）
        $customerName = '';
        try {
            $stC = $pdo->prepare("SELECT name FROM customers WHERE id=?");
            $stC->execute([(int)$customerId]);
            $customerName = (string)($stC->fetchColumn() ?: '');
        } catch (Throwable $e) {
            $customerName = '';
        }
        if ($customerName === '') $customerName = 'UNKNOWN';

        // 送信対象が空なら送らない（DBが正なので、ここで空＝通知不要）
        if (!empty($assigneeIdsDb)) {
            $payload = [
                'title' => 'TaskApp',
'body'  => 'New Task: ' . $customerName . ' / ' . (string)$task_title,
                'url'   => '/board.php?task_id=' . (int)$taskId,
            ];
            push_send_to_users($assigneeIdsDb, $payload);
        }
    } catch (Throwable $e) {
        error_log('[push] send error: ' . $e->getMessage());
    }

json_exit(500, [
    'ok' => false,
    // board.php は j.error しか表示しないので、ここに原因全文を入れる
    'error' => 'SERVER_ERROR: ' . $e->getMessage(),
    'code'  => 'SERVER_ERROR',
]);
}
