CREATE TABLE IF NOT EXISTS qipai_cleaning_settlement_reversals (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  tenant_id BIGINT UNSIGNED NOT NULL,
  reversal_no VARCHAR(64) NOT NULL,
  settlement_id BIGINT UNSIGNED NOT NULL,
  amount_delta_cents BIGINT NOT NULL,
  reason VARCHAR(512) NOT NULL,
  reversed_by BIGINT UNSIGNED NOT NULL,
  created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  CONSTRAINT fk_qipai_cleaning_settlement_reversal_tenant FOREIGN KEY (tenant_id)
    REFERENCES qipai_tenants(id),
  CONSTRAINT fk_qipai_cleaning_settlement_reversal_settlement FOREIGN KEY (settlement_id)
    REFERENCES qipai_cleaning_settlements(id),
  CONSTRAINT fk_qipai_cleaning_settlement_reversal_actor FOREIGN KEY (reversed_by)
    REFERENCES qipai_users(id),
  CONSTRAINT chk_qipai_cleaning_settlement_reversal_amount CHECK (amount_delta_cents <= 0),
  UNIQUE KEY uq_qipai_cleaning_settlement_reversal_no (tenant_id, reversal_no),
  UNIQUE KEY uq_qipai_cleaning_settlement_reversal_parent (tenant_id, settlement_id),
  KEY idx_qipai_cleaning_settlement_reversal_created (tenant_id, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS qipai_cleaning_settlement_events (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  tenant_id BIGINT UNSIGNED NOT NULL,
  settlement_id BIGINT UNSIGNED NOT NULL,
  from_status VARCHAR(32) NULL,
  to_status VARCHAR(32) NOT NULL,
  action VARCHAR(32) NOT NULL,
  actor_id BIGINT UNSIGNED NOT NULL,
  actor_type VARCHAR(16) NOT NULL DEFAULT 'USER',
  trace_id VARCHAR(64) NOT NULL,
  note VARCHAR(512) NOT NULL DEFAULT '',
  metadata JSON NOT NULL,
  created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  CONSTRAINT fk_qipai_cleaning_settlement_event_tenant FOREIGN KEY (tenant_id)
    REFERENCES qipai_tenants(id),
  CONSTRAINT fk_qipai_cleaning_settlement_event_parent FOREIGN KEY (settlement_id)
    REFERENCES qipai_cleaning_settlements(id),
  CONSTRAINT fk_qipai_cleaning_settlement_event_actor FOREIGN KEY (actor_id)
    REFERENCES qipai_users(id),
  CONSTRAINT chk_qipai_cleaning_settlement_event_actor_type CHECK (
    actor_type IN ('USER', 'SYSTEM')
  ),
  UNIQUE KEY uq_qipai_cleaning_settlement_event_trace
    (tenant_id, settlement_id, action, trace_id),
  KEY idx_qipai_cleaning_settlement_event_history
    (tenant_id, settlement_id, created_at, id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

ALTER TABLE qipai_cleaning_settlements
  ADD COLUMN cancelled_by BIGINT UNSIGNED NULL AFTER paid_by,
  ADD COLUMN cancelled_at DATETIME(3) NULL AFTER paid_at,
  ADD COLUMN payout_request_no VARCHAR(64) NOT NULL DEFAULT '' AFTER payout_channel,
  ADD COLUMN payout_request_key VARCHAR(128)
    GENERATED ALWAYS AS (
      CASE WHEN payout_request_no <> ''
        THEN CONCAT(payout_channel, ':', payout_request_no)
        ELSE NULL
      END
    ) STORED AFTER payout_request_no,
  ADD CONSTRAINT fk_qipai_cleaning_settlements_cancelled_by FOREIGN KEY (cancelled_by)
    REFERENCES qipai_users(id),
  ADD KEY idx_qipai_cleaning_settlement_cancelled (tenant_id, status, cancelled_at),
  ADD UNIQUE KEY uq_qipai_cleaning_settlement_payout_request
    (tenant_id, payout_request_key);

ALTER TABLE qipai_cleaning_settlement_items
  DROP INDEX uq_qipai_cleaning_settlement_item_task_user,
  ADD COLUMN reversal_id BIGINT UNSIGNED NULL AFTER reward_cents,
  ADD COLUMN reversed_at DATETIME(3) NULL AFTER reversal_id,
  ADD COLUMN active_share_key VARCHAR(128)
    GENERATED ALWAYS AS (
      CASE WHEN reversed_at IS NULL
        THEN CONCAT(CAST(task_id AS CHAR), ':', CAST(cleaner_user_id AS CHAR))
        ELSE NULL
      END
    ) STORED AFTER reversed_at,
  ADD CONSTRAINT fk_qipai_cleaning_settlement_items_reversal FOREIGN KEY (reversal_id)
    REFERENCES qipai_cleaning_settlement_reversals(id),
  ADD UNIQUE KEY uq_qipai_cleaning_settlement_active_share (tenant_id, active_share_key),
  ADD KEY idx_qipai_cleaning_settlement_item_reversal (tenant_id, reversal_id);

UPDATE qipai_cleaning_settlements
SET cancelled_by = generated_by,
    cancelled_at = COALESCE(cancelled_at, updated_at)
WHERE status = 'CANCELLED' AND cancelled_by IS NULL;

INSERT IGNORE INTO qipai_cleaning_settlement_reversals
  (tenant_id, reversal_no, settlement_id, amount_delta_cents, reason, reversed_by, created_at)
SELECT s.tenant_id, CONCAT('CLR-M09C-', s.id), s.id, -CAST(s.total_reward_cents AS SIGNED),
       'M09-C historical cancellation baseline', s.cancelled_by,
       COALESCE(s.cancelled_at, s.updated_at)
FROM qipai_cleaning_settlements s
WHERE s.status = 'CANCELLED' AND s.deleted_at IS NULL;

UPDATE qipai_cleaning_settlement_items i
INNER JOIN qipai_cleaning_settlement_reversals r
  ON r.tenant_id = i.tenant_id AND r.settlement_id = i.settlement_id
SET i.reversal_id = r.id,
    i.reversed_at = r.created_at
WHERE i.reversed_at IS NULL;

UPDATE qipai_cleaning_task_members m
INNER JOIN qipai_cleaning_settlement_items i
  ON i.tenant_id = m.tenant_id AND i.task_id = m.task_id AND i.cleaner_user_id = m.user_id
INNER JOIN qipai_cleaning_settlements s
  ON s.tenant_id = i.tenant_id AND s.id = i.settlement_id AND s.deleted_at IS NULL
SET m.settled_at = CASE
  WHEN s.status = 'PAID' AND i.reversed_at IS NULL
    THEN COALESCE(s.paid_at, m.settled_at, UTC_TIMESTAMP(3))
  ELSE NULL
END
WHERE i.id IS NOT NULL;

UPDATE qipai_cleaning_tasks t
SET t.status = 'COMPLETED', t.settled_at = NULL
WHERE t.status = 'SETTLED'
  AND EXISTS (
    SELECT 1
    FROM qipai_cleaning_task_members pending
    WHERE pending.tenant_id = t.tenant_id AND pending.task_id = t.id
      AND pending.removed_at IS NULL AND pending.reward_cents > 0
      AND pending.settled_at IS NULL
  );

INSERT IGNORE INTO qipai_cleaning_settlement_events
  (tenant_id, settlement_id, from_status, to_status, action, actor_id,
   actor_type, trace_id, note, metadata, created_at)
SELECT s.tenant_id, s.id, NULL, s.status, 'MIGRATE', s.generated_by, 'SYSTEM',
       CONCAT('m09c-', s.id), 'M09-C settlement history baseline',
       JSON_OBJECT('source', '2026081006'), s.created_at
FROM qipai_cleaning_settlements s
WHERE s.deleted_at IS NULL;

INSERT IGNORE INTO qipai_schema_migrations (version, name)
VALUES ('2026081006', 'm09c_cleaning_settlement_integrity');
