-- ============================================================
-- 12_v3_target_tables.sql
-- V3.0 目标管理系统表族 + 调度任务表 + 预警规则表
-- ============================================================

-- ============================================================
-- 1. 目标管理系统表族 (T-101 ~ T-105)
-- ============================================================

-- T-101: 年度战略目标
CREATE TABLE IF NOT EXISTS analytics.v3_annual_target (
  id SERIAL PRIMARY KEY,
  year INT NOT NULL,
  metric TEXT NOT NULL,              -- revenue / profit / store_count / member_count
  target_value NUMERIC(14,2) NOT NULL,
  description TEXT,
  created_by TEXT DEFAULT 'system',
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(year, metric)
);

-- T-102: 区域年度目标
CREATE TABLE IF NOT EXISTS analytics.v3_regional_target (
  id SERIAL PRIMARY KEY,
  year INT NOT NULL,
  region TEXT NOT NULL,
  revenue_target NUMERIC(14,2) NOT NULL,
  profit_target NUMERIC(14,2),
  store_count_target INT,
  member_count_target INT,
  weight_pct NUMERIC(5,2) DEFAULT 100,  -- 区域占比权重
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(year, region)
);

-- T-103: 门店月度目标（兼容现有 dim_store_target）
CREATE TABLE IF NOT EXISTS analytics.v3_store_monthly_target (
  id SERIAL PRIMARY KEY,
  year INT NOT NULL,
  month DATE NOT NULL,               -- YYYY-MM-01
  store_code TEXT NOT NULL,
  store_name TEXT,
  region TEXT,
  grade TEXT DEFAULT 'B',            -- A/B/C/D 分级
  revenue_target NUMERIC(14,2) NOT NULL,
  bill_count_target INT,
  avg_bill_value_target NUMERIC(8,2),
  member_penetration_target NUMERIC(5,2),
  cost_rate_target NUMERIC(5,2),
  profit_target NUMERIC(14,2),
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(month, store_code)
);

-- T-104: 日级目标
CREATE TABLE IF NOT EXISTS analytics.v3_daily_target (
  id SERIAL PRIMARY KEY,
  target_date DATE NOT NULL,
  store_code TEXT NOT NULL,
  store_name TEXT,
  revenue_target NUMERIC(12,2) NOT NULL,
  bill_count_target INT,
  avg_bill_value_target NUMERIC(8,2),
  package_target NUMERIC(12,2),       -- 套餐目标
  loss_target NUMERIC(8,2),            -- 损耗目标
  arrival_target NUMERIC(8,2),         -- 到货目标
  weight_pct NUMERIC(5,2) DEFAULT 0,   -- 当日占月度权重
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(target_date, store_code)
);

-- T-105: 个人任务
CREATE TABLE IF NOT EXISTS analytics.v3_personal_task (
  id SERIAL PRIMARY KEY,
  target_date DATE NOT NULL,
  store_code TEXT NOT NULL,
  employee_name TEXT NOT NULL,
  position TEXT,                       -- 岗位
  metric TEXT NOT NULL,                -- 指标名
  target_value NUMERIC(12,2) NOT NULL,
  actual_value NUMERIC(12,2),
  completion_rate NUMERIC(5,2),        -- 完成率%
  status TEXT DEFAULT '待执行',
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- ============================================================
-- 2. 调度任务注册表 (T-121)
-- ============================================================

CREATE TABLE IF NOT EXISTS analytics.v3_scheduled_task (
  id SERIAL PRIMARY KEY,
  task_name TEXT NOT NULL UNIQUE,
  description TEXT,
  cron_expr TEXT NOT NULL,             -- cron 表达式
  handler TEXT NOT NULL,               -- 处理函数标识
  is_enabled BOOLEAN DEFAULT true,
  last_run_at TIMESTAMPTZ,
  next_run_at TIMESTAMPTZ,
  last_status TEXT,                    -- success / failed / running
  last_error TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- ============================================================
-- 3. 预警规则引擎表族 (T-130 ~ T-131)
-- ============================================================

-- T-130: 预警规则
CREATE TABLE IF NOT EXISTS analytics.v3_alert_rule (
  id SERIAL PRIMARY KEY,
  rule_name TEXT NOT NULL,
  description TEXT,
  metric TEXT NOT NULL,                -- 监控指标
  operator TEXT NOT NULL DEFAULT '<',  -- < / <= / > / >= / =
  threshold NUMERIC(14,2) NOT NULL,    -- 阈值
  severity TEXT DEFAULT 'yellow',      -- red / yellow
  push_targets TEXT,                   -- 推送对象（逗号分隔角色）
  escalation_path TEXT,                -- 升级路径
  is_enabled BOOLEAN DEFAULT true,
  check_interval TEXT DEFAULT 'hourly', -- hourly / daily / weekly / monthly
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- T-131: 预警日志
CREATE TABLE IF NOT EXISTS analytics.v3_alert_log (
  id SERIAL PRIMARY KEY,
  rule_id INT REFERENCES analytics.v3_alert_rule(id) ON DELETE CASCADE,
  rule_name TEXT,
  store_code TEXT,
  store_name TEXT,
  metric_value NUMERIC(14,2),
  threshold NUMERIC(14,2),
  severity TEXT,
  push_status TEXT DEFAULT 'pending',  -- pending / sent / failed
  handle_status TEXT DEFAULT 'pending', -- pending / handling / resolved / ignored
  handle_comment TEXT,
  triggered_at TIMESTAMPTZ DEFAULT NOW(),
  handled_at TIMESTAMPTZ
);

-- ============================================================
-- 4. 门店自动分级表 (T-160)
-- ============================================================

CREATE TABLE IF NOT EXISTS analytics.v3_store_grade (
  id SERIAL PRIMARY KEY,
  grade_month DATE NOT NULL,
  store_code TEXT NOT NULL,
  store_name TEXT,
  region TEXT,
  grade TEXT NOT NULL,                 -- A / B / C / D
  revenue_achievement_pct NUMERIC(5,2),
  inspection_score NUMERIC(5,2),
  complaint_rate NUMERIC(5,2),
  overall_score NUMERIC(5,2),
  reason TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(grade_month, store_code)
);

-- ============================================================
-- 索引
-- ============================================================
CREATE INDEX IF NOT EXISTS idx_v3_annual_target_year ON analytics.v3_annual_target(year);
CREATE INDEX IF NOT EXISTS idx_v3_regional_target_year ON analytics.v3_regional_target(year);
CREATE INDEX IF NOT EXISTS idx_v3_store_monthly_target_month ON analytics.v3_store_monthly_target(month);
CREATE INDEX IF NOT EXISTS idx_v3_store_monthly_target_store ON analytics.v3_store_monthly_target(store_code);
CREATE INDEX IF NOT EXISTS idx_v3_daily_target_date ON analytics.v3_daily_target(target_date);
CREATE INDEX IF NOT EXISTS idx_v3_daily_target_store ON analytics.v3_daily_target(store_code);
CREATE INDEX IF NOT EXISTS idx_v3_personal_task_date ON analytics.v3_personal_task(target_date);
CREATE INDEX IF NOT EXISTS idx_v3_personal_task_store ON analytics.v3_personal_task(store_code);
CREATE INDEX IF NOT EXISTS idx_v3_scheduled_task_enabled ON analytics.v3_scheduled_task(is_enabled);
CREATE INDEX IF NOT EXISTS idx_v3_alert_rule_enabled ON analytics.v3_alert_rule(is_enabled);
CREATE INDEX IF NOT EXISTS idx_v3_alert_log_rule ON analytics.v3_alert_log(rule_id);
CREATE INDEX IF NOT EXISTS idx_v3_alert_log_triggered ON analytics.v3_alert_log(triggered_at);
CREATE INDEX IF NOT EXISTS idx_v3_alert_log_handle_status ON analytics.v3_alert_log(handle_status);
CREATE INDEX IF NOT EXISTS idx_v3_store_grade_month ON analytics.v3_store_grade(grade_month);
CREATE INDEX IF NOT EXISTS idx_v3_store_grade_store ON analytics.v3_store_grade(store_code);

-- ============================================================
-- 初始化默认调度任务
-- ============================================================
INSERT INTO analytics.v3_scheduled_task (task_name, description, cron_expr, handler, is_enabled) VALUES
  ('daily_report', '每日08:30生成昨日日报', '30 8 * * *', 'dailyReport', true),
  ('daily_target_card', '每日09:00生成日目标卡', '0 9 * * *', 'dailyTargetCard', true),
  ('hourly_achievement_check', '每小时比对日目标达成率', '0 * * * *', 'hourlyAchievementCheck', true),
  ('daily_review_template', '每日22:30生成日复盘模板', '30 22 * * *', 'dailyReviewTemplate', false),
  ('weekly_data_package', '每周一09:00生成上周数据包', '0 9 * * 1', 'weeklyDataPackage', false),
  ('monthly_business_report', '每月1日09:00生成月度经营分析报告', '0 9 1 * *', 'monthlyBusinessReport', false),
  ('monthly_mid_progress', '每月15日14:00生成月中进度报告', '0 14 15 * *', 'monthlyMidProgress', false),
  ('alert_engine_scan', '每5分钟扫描预警规则', '*/5 * * * *', 'alertEngineScan', true)
ON CONFLICT (task_name) DO NOTHING;

-- ============================================================
-- 初始化默认预警规则
-- ============================================================
INSERT INTO analytics.v3_alert_rule (rule_name, description, metric, operator, threshold, severity, push_targets, check_interval) VALUES
  ('营收达成率红灯', '日营收达成率低于80%触发红灯', 'revenue_achievement_pct', '<', 80, 'red', 'store,regional', 'hourly'),
  ('营收达成率黄灯', '日营收达成率低于90%触发黄灯', 'revenue_achievement_pct', '<', 90, 'yellow', 'store', 'hourly'),
  ('毛利率异常', '理论毛利率低于40%', 'theoretical_margin_pct', '<', 40, 'yellow', 'store,regional', 'daily'),
  ('会员渗透率低', '会员账单占比低于20%', 'member_bill_share_pct', '<', 20, 'yellow', 'store', 'daily'),
  ('客诉率偏高', '客诉率超过5%', 'complaint_rate', '>', 5, 'red', 'store,regional,hq', 'daily'),
  ('巡检低分', '食安巡检得分低于90', 'inspection_score', '<', 90, 'red', 'store,regional', 'daily'),
  ('离职率偏高', '月度离职率超过15%', 'turnover_rate', '>', 15, 'red', 'regional,hq', 'monthly')
ON CONFLICT DO NOTHING;
