-- Petstore Phase 1：可执行回访任务与再次预约归因
-- 前置：20260802_create_store_customer_timeline.sql 已执行。
-- ReportLead 保留宠主同意/来源事实；FollowUpTask 承载门店操作状态。

CREATE TABLE t_follow_up_task (
    id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    task_id VARCHAR(36) NOT NULL,
    store_id BIGINT NOT NULL,
    store_customer_id BIGINT NOT NULL,
    source_lead_id BIGINT NOT NULL,
    source_report_id BIGINT NULL,
    status VARCHAR(16) NOT NULL COMMENT 'pending | in_progress | completed | canceled',
    outcome VARCHAR(24) NULL COMMENT 'rebooked | not_interested | invalid_contact | unsubscribed',
    due_date DATE NOT NULL,
    assigned_user_id BIGINT NULL,
    attempt_count INT NOT NULL DEFAULT 0,
    last_attempt_outcome VARCHAR(24) NULL COMMENT 'no_answer | follow_later',
    last_contacted_at DATETIME NULL,
    last_contacted_by_user_id BIGINT NULL,
    closed_at DATETIME NULL,
    closed_by_user_id BIGINT NULL,
    rebooked_appointment_id BIGINT NULL,
    create_time DATETIME NOT NULL,
    update_time DATETIME NOT NULL,
    version BIGINT NOT NULL DEFAULT 0,
    CONSTRAINT uk_follow_up_task_public_id UNIQUE (task_id),
    INDEX idx_follow_up_store_status_due (store_id, status, due_date),
    INDEX idx_follow_up_customer_status (store_customer_id, status),
    INDEX idx_follow_up_lead_status (source_lead_id, status),
    INDEX idx_follow_up_rebook (rebooked_appointment_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门店回访执行任务';

-- 只为仍待处理的历史留资建立开放任务；不得猜测已发送/取消记录的真实结果。
INSERT INTO t_follow_up_task (
    task_id, store_id, store_customer_id, source_lead_id, source_report_id,
    status, outcome, due_date, assigned_user_id, attempt_count,
    last_attempt_outcome, last_contacted_at, last_contacted_by_user_id,
    closed_at, closed_by_user_id, rebooked_appointment_id,
    create_time, update_time, version
)
SELECT
    UUID(),
    l.store_id,
    sc.id,
    l.id,
    l.report_id,
    'pending',
    NULL,
    COALESCE(l.remind_date, CURRENT_DATE),
    NULL,
    0,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    COALESCE(l.create_time, l.update_time, NOW()),
    COALESCE(l.update_time, l.create_time, NOW()),
    0
FROM t_report_lead l
JOIN t_store_customer sc
  ON sc.store_id = l.store_id
 AND sc.phone = l.phone
 AND sc.deleted = 0
WHERE l.store_id IS NOT NULL
  AND l.remind_status = 'pending';

-- 历史开放任务形成可靠的 task_created 事实；不复制手机号、IP、token 或微信标识。
INSERT INTO t_business_event (
    event_id, event_type, event_version, store_id, store_customer_id,
    aggregate_type, aggregate_id, actor_user_id, actor_role, source,
    occurred_at, metadata_json, idempotency_key, create_time
)
SELECT
    UUID(),
    'follow_up_created',
    1,
    t.store_id,
    t.store_customer_id,
    'follow_up_task',
    t.id,
    NULL,
    NULL,
    'migration',
    t.create_time,
    CONCAT('{"dueDate":"', t.due_date, '"}'),
    CONCAT('follow_up_created:', t.id),
    NOW()
FROM t_follow_up_task t;

-- 验证：以下五项必须全部为 0。
SELECT COUNT(*) AS pending_leads_without_open_task_count
FROM t_report_lead l
LEFT JOIN t_follow_up_task t
  ON t.source_lead_id = l.id
 AND t.status IN ('pending', 'in_progress')
WHERE l.store_id IS NOT NULL
  AND l.remind_status = 'pending'
  AND t.id IS NULL;

SELECT COUNT(*) AS invalid_follow_up_customer_scope_count
FROM t_follow_up_task t
LEFT JOIN t_store_customer sc
  ON sc.id = t.store_customer_id
 AND sc.store_id = t.store_id
LEFT JOIN t_store_customer canonical
  ON canonical.id = CASE
      WHEN sc.deleted = 0 THEN sc.id
      ELSE sc.merged_into_store_customer_id
  END
 AND canonical.store_id = t.store_id
 AND canonical.deleted = 0
 AND canonical.merged_into_store_customer_id IS NULL
WHERE sc.id IS NULL OR canonical.id IS NULL;

SELECT COUNT(*) AS invalid_follow_up_state_count
FROM t_follow_up_task t
WHERE t.status NOT IN ('pending', 'in_progress', 'completed', 'canceled')
   OR (t.status IN ('pending', 'in_progress')
       AND (t.outcome IS NOT NULL OR t.closed_at IS NOT NULL OR t.closed_by_user_id IS NOT NULL
            OR t.rebooked_appointment_id IS NOT NULL))
   OR (t.status = 'pending' AND t.assigned_user_id IS NOT NULL)
   OR (t.status = 'in_progress' AND t.assigned_user_id IS NULL)
   OR (t.status = 'completed'
       AND (COALESCE(t.outcome, '') NOT IN ('rebooked', 'not_interested', 'invalid_contact')
            OR t.closed_at IS NULL OR t.closed_by_user_id IS NULL
            OR t.last_contacted_at IS NULL OR t.last_contacted_by_user_id IS NULL
            OR t.attempt_count < 1))
   OR (t.status = 'canceled'
       AND (COALESCE(t.outcome, '') <> 'unsubscribed' OR t.closed_at IS NULL
            OR t.closed_by_user_id IS NOT NULL))
   OR (t.last_attempt_outcome IS NOT NULL
       AND (t.last_attempt_outcome NOT IN ('no_answer', 'follow_later')
            OR t.last_contacted_at IS NULL OR t.last_contacted_by_user_id IS NULL))
   OR (t.outcome = 'rebooked' AND t.rebooked_appointment_id IS NULL)
   OR (COALESCE(t.outcome, '') <> 'rebooked' AND t.rebooked_appointment_id IS NOT NULL)
   OR (t.rebooked_appointment_id IS NOT NULL AND NOT EXISTS (
       SELECT 1
       FROM t_appointment a
       WHERE a.id = t.rebooked_appointment_id
         AND a.store_id = t.store_id
         AND a.deleted = 0
   ))
   OR t.attempt_count < 0;

SELECT COUNT(*) AS duplicate_open_follow_up_task_count
FROM (
    SELECT source_lead_id
    FROM t_follow_up_task
    WHERE status IN ('pending', 'in_progress')
    GROUP BY source_lead_id
    HAVING COUNT(*) > 1
) duplicated;

SELECT COUNT(*) AS follow_up_tasks_without_created_event_count
FROM t_follow_up_task t
LEFT JOIN t_business_event e
  ON e.idempotency_key = CONCAT('follow_up_created:', t.id)
 AND e.event_type = 'follow_up_created'
 AND e.store_id = t.store_id
 AND e.aggregate_type = 'follow_up_task'
 AND e.aggregate_id = t.id
WHERE e.id IS NULL;
