-- ============================================================
-- Homecare Migration SQL - Phase 1 (Location & Checkin)
-- Date: 2026-06-05
-- Purpose: Formal migration for homecare location distance phase 1
-- Scope: Create/alter tables, indexes, foreign keys, seed data
-- ID Type: All user/org/team/elder IDs unified to uuid
-- Checkin Radius: 50 meters (phase 1)
-- ============================================================

BEGIN;

-- Needed for gen_random_uuid() defaults used by UUID primary keys.
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- ============================================================
-- Part 1: Create/Alter Foundation Tables
-- ============================================================

-- Table: public.hc_work_order_events
-- Source: 20260518_homecare_foundation.sql
CREATE TABLE IF NOT EXISTS public.hc_work_order_events (
  id text primary key,
  work_order_id uuid not null,
  org_id uuid not null,
  team_id uuid,
  worker_id uuid,
  action text not null,
  from_status text not null,
  to_status text not null,
  operator_id uuid not null,
  reason text,
  payload jsonb,
  created_at timestamptz not null default now()
);

-- Table: public.hc_work_order_exceptions
-- Source: 20260518_homecare_foundation.sql
CREATE TABLE IF NOT EXISTS public.hc_work_order_exceptions (
  id text primary key,
  work_order_id uuid not null,
  org_id uuid not null,
  team_id uuid,
  worker_id uuid,
  exception_type text not null,
  description text not null,
  status text not null default 'PENDING' check (status in ('PENDING', 'HANDLED')),
  decision text,
  reason text,
  created_by uuid not null,
  handled_by uuid,
  evidence_urls jsonb not null default '[]'::jsonb,
  created_at timestamptz not null default now(),
  handled_at timestamptz
);

-- Table: public.hc_evidence_files
-- Source: 20260518_homecare_foundation.sql
-- Phase 1 Update: Add fields for checkin evidence support
CREATE TABLE IF NOT EXISTS public.hc_evidence_files (
  id text primary key,
  work_order_id uuid not null,
  org_id uuid not null,
  owner_id uuid,
  uploader_id uuid not null,
  file_url text not null,
  mime_type text,
  evidence_type text,
  -- Phase 1新增字段
  file_size_bytes bigint not null default 0,
  upload_status text not null default 'TEMP' check (upload_status in ('TEMP', 'READY', 'BOUND', 'LOCKED', 'DELETED')),
  storage_bucket text,
  storage_path text,
  file_hash text,
  bound_action text check (bound_action in ('CHECKIN', 'CHECKOUT', 'EXCEPTION')),
  bound_record_id text,
  is_locked boolean not null default false,
  locked_at timestamptz,
  expires_at timestamptz,
  updated_at timestamptz not null default now(),
  created_at timestamptz not null default now()
);

-- Table: public.hc_worker_qualifications
-- Source: 20260518_homecare_foundation.sql
CREATE TABLE IF NOT EXISTS public.hc_worker_qualifications (
  id text primary key,
  org_id uuid not null,
  worker_id uuid not null,
  qualification_type text not null,
  qualification_no text,
  issue_org text,
  valid_from date,
  valid_to date,
  review_status text not null default 'PENDING' check (review_status in ('PENDING', 'APPROVED', 'REJECTED', 'EXPIRED')),
  reviewed_by uuid,
  reviewed_at timestamptz,
  file_urls jsonb not null default '[]'::jsonb,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.hc_settlements
-- Source: 20260518_homecare_foundation.sql
CREATE TABLE IF NOT EXISTS public.hc_settlements (
  id uuid primary key default gen_random_uuid(),
  work_order_id uuid not null unique,
  org_id uuid not null,
  finance_owner_id uuid,
  status text not null default 'PENDING' check (status in ('PENDING', 'READY', 'CONFIRMED')),
  amount numeric(12, 2) not null default 0,
  currency text not null default 'CNY',
  settled_at timestamptz,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- ============================================================
-- Part 2: Business Closure Extension Tables
-- ============================================================

-- Table: public.hc_acceptances
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_acceptances (
  id text primary key,
  work_order_id uuid not null,
  org_id uuid not null,
  team_id uuid,
  worker_id uuid,
  status text not null default 'PENDING' check (status in ('PENDING', 'ACCEPTED', 'REJECTED', 'CLOSED')),
  result text check (result in ('PASS', 'REJECT')),
  rating smallint check (rating between 1 and 5),
  tags jsonb not null default '[]'::jsonb,
  comment text,
  rejected_reason text,
  accepted_by uuid,
  accepted_at timestamptz,
  created_by uuid,
  updated_by uuid,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.hc_acceptance_issues
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_acceptance_issues (
  id text primary key,
  acceptance_id text not null,
  work_order_id uuid not null,
  org_id uuid not null,
  team_id uuid,
  worker_id uuid,
  issue_type text not null,
  priority text,
  description text not null,
  evidence_urls jsonb not null default '[]'::jsonb,
  status text not null default 'OPEN' check (status in ('OPEN', 'PROCESSING', 'RESOLVED', 'CLOSED')),
  reporter_id uuid not null,
  handler_id uuid,
  resolution text,
  resolved_at timestamptz,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.hc_complaints
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_complaints (
  id text primary key,
  work_order_id uuid,
  acceptance_issue_id text,
  org_id uuid not null,
  team_id uuid,
  worker_id uuid,
  complainant_id uuid not null,
  complaint_type text not null,
  description text not null,
  evidence_urls jsonb not null default '[]'::jsonb,
  status text not null default 'PENDING' check (status in ('PENDING', 'PROCESSING', 'RESOLVED', 'CLOSED')),
  handler_id uuid,
  resolution text,
  resolved_at timestamptz,
  created_by uuid,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.hc_exception_actions
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_exception_actions (
  id text primary key,
  exception_id text not null,
  work_order_id uuid not null,
  org_id uuid not null,
  team_id uuid,
  worker_id uuid,
  action_type text not null,
  description text,
  payload jsonb not null default '{}'::jsonb,
  operator_id uuid not null,
  created_at timestamptz not null default now()
);

-- Table: public.hc_settlement_items
CREATE TABLE IF NOT EXISTS public.hc_settlement_items (
  id uuid primary key default gen_random_uuid(),
  settlement_id uuid not null,
  work_order_id uuid not null,
  execution_record_id uuid,
  item_name text not null,
  unit_price numeric(12, 2) not null default 0,
  quantity numeric(10, 2) not null default 1,
  actual_amount numeric(12, 2) not null default 0,
  deduction_amount numeric(12, 2) not null default 0,
  self_pay_amount numeric(12, 2) not null default 0,
  status text not null default 'PENDING' check (status in ('PENDING', 'APPROVED', 'REJECTED', 'WAIVED')),
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.hc_payments
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_payments (
  id uuid primary key default gen_random_uuid(),
  settlement_id uuid not null,
  org_id uuid not null,
  payer_id uuid,
  payment_channel text not null,
  transaction_id text,
  amount numeric(12, 2) not null,
  status text not null default 'PENDING' check (status in ('PENDING', 'PAID', 'FAILED', 'CANCELLED', 'REFUNDING', 'REFUNDED')),
  callback_payload jsonb not null default '{}'::jsonb,
  paid_at timestamptz,
  failed_at timestamptz,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.hc_refunds
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_refunds (
  id uuid primary key default gen_random_uuid(),
  payment_id uuid not null,
  settlement_id uuid not null,
  org_id uuid not null,
  amount numeric(12, 2) not null,
  reason text not null,
  status text not null default 'PENDING' check (status in ('PENDING', 'PROCESSING', 'REFUNDED', 'FAILED', 'CLOSED')),
  refund_transaction_id text,
  created_by uuid,
  refunded_at timestamptz,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.hc_ledgers
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_ledgers (
  id uuid primary key default gen_random_uuid(),
  settlement_id uuid not null,
  org_id uuid not null,
  archive_period text not null,
  ledger_type text not null default 'SETTLEMENT',
  content jsonb not null default '{}'::jsonb,
  archived_at timestamptz,
  created_by uuid,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.hc_archive_files
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_archive_files (
  id uuid primary key default gen_random_uuid(),
  ledger_id uuid not null,
  org_id uuid not null,
  file_url text not null,
  file_name text,
  file_size bigint,
  mime_type text,
  created_by uuid,
  created_at timestamptz not null default now()
);

-- Table: public.hc_consent_records
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_consent_records (
  id text primary key,
  org_id uuid not null,
  elder_id uuid not null,
  consent_type text not null,
  consent_status text not null default 'GRANTED' check (consent_status in ('GRANTED', 'REVOKED', 'EXPIRED')),
  consent_version text,
  granted_by uuid,
  granted_at timestamptz,
  revoked_at timestamptz,
  expires_at timestamptz,
  evidence_urls jsonb not null default '[]'::jsonb,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- ============================================================
-- Part 3: Location Distance Phase 1 Tables
-- ============================================================

-- Table: public.hc_dispatch_assignments
-- Source: 20260602_homecare_location_distance_phase1_tables.sql
CREATE TABLE IF NOT EXISTS public.hc_dispatch_assignments (
  id text primary key,
  work_order_id uuid not null,
  org_id uuid not null,
  team_id uuid,
  assign_version integer not null default 1 check (assign_version > 0),
  worker_id uuid,
  service_latitude numeric(10,7) not null,
  service_longitude numeric(10,7) not null,
  service_coordinate_type text not null default 'gcj02',
  dispatch_status text not null default 'PENDING'
    check (dispatch_status in ('PENDING', 'ACCEPTED', 'REJECTED', 'TIMEOUT', 'REASSIGNED', 'CANCELLED')),
  dispatch_reason text,
  is_current boolean not null default true,
  dispatched_at timestamptz not null default now(),
  accepted_at timestamptz,
  rejected_at timestamptz,
  timeout_at timestamptz,
  reassigned_at timestamptz,
  cancelled_at timestamptz,
  created_by uuid,
  updated_by uuid,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  constraint chk_hc_dispatch_assignments_lat_range check (service_latitude between -90 and 90),
  constraint chk_hc_dispatch_assignments_lng_range check (service_longitude between -180 and 180),
  constraint uq_hc_dispatch_assignments_version unique (work_order_id, assign_version)
);

-- Table: public.hc_worker_locations
-- Source: 20260602_homecare_location_distance_phase1_tables.sql
CREATE TABLE IF NOT EXISTS public.hc_worker_locations (
  id text primary key,
  work_order_id uuid not null,
  worker_id uuid not null,
  latitude numeric(10,7) not null,
  longitude numeric(10,7) not null,
  coordinate_type text not null default 'gcj02',
  accuracy numeric(10,2),
  location_scene text not null
    check (location_scene in ('ON_THE_WAY', 'CHECKIN_PRECHECK', 'CHECKIN', 'CHECKOUT')),
  reported_at timestamptz not null,
  distance_meters numeric(10,2),
  formatted_address text,
  province text,
  city text,
  district text,
  street text,
  poi_title text,
  geocode_provider text,
  geocode_status text,
  address_updated_at timestamptz,
  created_at timestamptz not null default now(),
  constraint chk_hc_worker_locations_lat_range check (latitude between -90 and 90),
  constraint chk_hc_worker_locations_lng_range check (longitude between -180 and 180)
);

-- Table: public.hc_work_order_confirmations
-- Source: 20260602_homecare_location_distance_phase1_tables.sql
CREATE TABLE IF NOT EXISTS public.hc_work_order_confirmations (
  id text primary key,
  work_order_id uuid not null,
  confirmation_type text not null default 'ARRIVAL',
  status text not null default 'PENDING'
    check (status in ('PENDING', 'CONFIRMED', 'REJECTED')),
  confirmed_by uuid,
  confirmed_at timestamptz,
  reason text,
  payload jsonb not null default '{}'::jsonb,
  -- Phase 1预留：二期电子签名扩展字段
  signature_url text,
  signature_hash text,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

-- Table: public.sys_sla_config
-- Source: 20260602_homecare_location_distance_phase1_tables.sql
CREATE TABLE IF NOT EXISTS public.sys_sla_config (
  id text primary key,
  config_key text not null,
  config_value text not null,
  value_type text not null default 'string',
  scope_type text not null default 'GLOBAL'
    check (scope_type in ('WORK_ORDER', 'ORG', 'TEAM', 'GLOBAL')),
  scope_id text,
  is_active boolean not null default true,
  description text,
  updated_by uuid,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  constraint chk_sys_sla_config_scope check (
    (scope_type = 'GLOBAL' and scope_id is null)
    or (scope_type <> 'GLOBAL')
  )
);

-- ============================================================
-- Part 4: Audit Extension Tables (if not exist)
-- ============================================================

-- Table: public.hc_state_transitions
CREATE TABLE IF NOT EXISTS public.hc_state_transitions (
  id text primary key,
  work_order_id uuid not null,
  from_status text not null,
  to_status text not null,
  triggered_by uuid not null,
  reason text,
  payload jsonb,
  created_at timestamptz not null default now()
);

-- Table: public.hc_audit_logs
CREATE TABLE IF NOT EXISTS public.hc_audit_logs (
  id text primary key,
  work_order_id uuid,
  org_id uuid,
  actor_id uuid not null,
  actor_role text not null,
  action text not null,
  resource_type text not null,
  resource_id text not null,
  details jsonb,
  ip_address inet,
  user_agent text,
  created_at timestamptz not null default now()
);

-- Table: public.hc_sensitive_access_logs
CREATE TABLE IF NOT EXISTS public.hc_sensitive_access_logs (
  id text primary key,
  accessor_id uuid not null,
  accessed_resource_type text not null,
  accessed_resource_id text not null,
  access_purpose text not null,
  approved_by uuid,
  created_at timestamptz not null default now()
);


-- ============================================================
-- Part 4.5: Legacy Compatibility Fixes
-- ============================================================
-- These fixes make reruns safe when older hc_* tables already exist.
-- CREATE TABLE IF NOT EXISTS does not upgrade existing table definitions,
-- so referenced columns and FK columns are normalized before indexes/FKs.

-- Existing settlements table may already have id uuid in current database.
-- If settlement-related child tables already exist with text FK columns,
-- convert them to uuid before FK creation. This succeeds only when existing
-- values are empty or valid UUID strings.
DO $$
BEGIN
  IF to_regclass('public.hc_settlement_items') IS NOT NULL
     AND EXISTS (
       SELECT 1 FROM information_schema.columns
       WHERE table_schema='public'
         AND table_name='hc_settlement_items'
         AND column_name='settlement_id'
         AND udt_name <> 'uuid'
     )
  THEN
    ALTER TABLE public.hc_settlement_items
      ALTER COLUMN settlement_id TYPE uuid USING NULLIF(settlement_id, '')::uuid;
  END IF;

  IF to_regclass('public.hc_payments') IS NOT NULL
     AND EXISTS (
       SELECT 1 FROM information_schema.columns
       WHERE table_schema='public'
         AND table_name='hc_payments'
         AND column_name='settlement_id'
         AND udt_name <> 'uuid'
     )
  THEN
    ALTER TABLE public.hc_payments
      ALTER COLUMN settlement_id TYPE uuid USING NULLIF(settlement_id, '')::uuid;
  END IF;

  IF to_regclass('public.hc_refunds') IS NOT NULL
     AND EXISTS (
       SELECT 1 FROM information_schema.columns
       WHERE table_schema='public'
         AND table_name='hc_refunds'
         AND column_name='settlement_id'
         AND udt_name <> 'uuid'
     )
  THEN
    ALTER TABLE public.hc_refunds
      ALTER COLUMN settlement_id TYPE uuid USING NULLIF(settlement_id, '')::uuid;
  END IF;

  IF to_regclass('public.hc_refunds') IS NOT NULL
     AND EXISTS (
       SELECT 1 FROM information_schema.columns
       WHERE table_schema='public'
         AND table_name='hc_refunds'
         AND column_name='payment_id'
         AND udt_name <> 'uuid'
     )
  THEN
    ALTER TABLE public.hc_refunds
      ALTER COLUMN payment_id TYPE uuid USING NULLIF(payment_id, '')::uuid;
  END IF;

  IF to_regclass('public.hc_ledgers') IS NOT NULL
     AND EXISTS (
       SELECT 1 FROM information_schema.columns
       WHERE table_schema='public'
         AND table_name='hc_ledgers'
         AND column_name='settlement_id'
         AND udt_name <> 'uuid'
     )
  THEN
    ALTER TABLE public.hc_ledgers
      ALTER COLUMN settlement_id TYPE uuid USING NULLIF(settlement_id, '')::uuid;
  END IF;

  IF to_regclass('public.hc_archive_files') IS NOT NULL
     AND EXISTS (
       SELECT 1 FROM information_schema.columns
       WHERE table_schema='public'
         AND table_name='hc_archive_files'
         AND column_name='ledger_id'
         AND udt_name <> 'uuid'
     )
  THEN
    ALTER TABLE public.hc_archive_files
      ALTER COLUMN ledger_id TYPE uuid USING NULLIF(ledger_id, '')::uuid;
  END IF;
END $$;

-- ============================================================
-- Part 5: Indexes
-- ============================================================

-- hc_dispatch_assignments indexes
CREATE INDEX IF NOT EXISTS idx_hc_dispatch_assignments_wo_created
  ON public.hc_dispatch_assignments (work_order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_dispatch_assignments_current
  ON public.hc_dispatch_assignments (work_order_id) WHERE is_current = true;

-- Ensure each work order has at most one current assignment for distance/checkin RPC lookup.
CREATE UNIQUE INDEX IF NOT EXISTS uq_hc_dispatch_assignments_one_current
  ON public.hc_dispatch_assignments (work_order_id) WHERE is_current = true;

CREATE INDEX IF NOT EXISTS idx_hc_dispatch_assignments_worker_status
  ON public.hc_dispatch_assignments (worker_id, dispatch_status, created_at DESC);

-- hc_worker_locations indexes
CREATE INDEX IF NOT EXISTS idx_hc_worker_locations_wo_reported
  ON public.hc_worker_locations (work_order_id, reported_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_worker_locations_worker_reported
  ON public.hc_worker_locations (worker_id, reported_at DESC);

-- hc_work_order_confirmations indexes
CREATE INDEX IF NOT EXISTS idx_hc_work_order_confirmations_wo_created
  ON public.hc_work_order_confirmations (work_order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_work_order_confirmations_status
  ON public.hc_work_order_confirmations (status, updated_at DESC);

-- hc_evidence_files indexes
CREATE INDEX IF NOT EXISTS idx_hc_evidence_files_wo_created
  ON public.hc_evidence_files (work_order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_evidence_files_upload_status
  ON public.hc_evidence_files (upload_status) WHERE upload_status != 'DELETED';

-- sys_sla_config indexes
CREATE INDEX IF NOT EXISTS idx_sys_sla_config_key_scope
  ON public.sys_sla_config (config_key, scope_type, scope_id, is_active) WHERE is_active = true;

-- hc_work_order_exceptions indexes
CREATE INDEX IF NOT EXISTS idx_hc_work_order_exceptions_wo_created
  ON public.hc_work_order_exceptions (work_order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_work_order_exceptions_status
  ON public.hc_work_order_exceptions (status, created_at DESC);

-- hc_work_order_events indexes
CREATE INDEX IF NOT EXISTS idx_hc_work_order_events_wo_created
  ON public.hc_work_order_events (work_order_id, created_at DESC);

-- hc_settlements indexes
CREATE INDEX IF NOT EXISTS idx_hc_settlements_wo
  ON public.hc_settlements (work_order_id);

-- ============================================================
-- Part 6: Foreign Keys
-- ============================================================

-- Make foreign key creation idempotent for reruns
ALTER TABLE public.hc_work_order_events
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_events_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_events_worker,
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_events_operator;

ALTER TABLE public.hc_work_order_exceptions
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_exceptions_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_exceptions_worker,
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_exceptions_created_by,
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_exceptions_handled_by;

ALTER TABLE public.hc_evidence_files
  DROP CONSTRAINT IF EXISTS fk_hc_evidence_files_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_evidence_files_uploader;

ALTER TABLE public.hc_worker_qualifications
  DROP CONSTRAINT IF EXISTS fk_hc_worker_qualifications_worker,
  DROP CONSTRAINT IF EXISTS fk_hc_worker_qualifications_reviewed_by;

ALTER TABLE public.hc_settlements
  DROP CONSTRAINT IF EXISTS fk_hc_settlements_work_order;

ALTER TABLE public.hc_acceptances
  DROP CONSTRAINT IF EXISTS fk_hc_acceptances_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_acceptances_worker,
  DROP CONSTRAINT IF EXISTS fk_hc_acceptances_accepted_by;

ALTER TABLE public.hc_acceptance_issues
  DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_acceptance,
  DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_worker,
  DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_reporter,
  DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_handler;

ALTER TABLE public.hc_complaints
  DROP CONSTRAINT IF EXISTS fk_hc_complaints_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_complaints_acceptance_issue,
  DROP CONSTRAINT IF EXISTS fk_hc_complaints_worker,
  DROP CONSTRAINT IF EXISTS fk_hc_complaints_complainant,
  DROP CONSTRAINT IF EXISTS fk_hc_complaints_handler;

ALTER TABLE public.hc_exception_actions
  DROP CONSTRAINT IF EXISTS fk_hc_exception_actions_exception,
  DROP CONSTRAINT IF EXISTS fk_hc_exception_actions_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_exception_actions_worker,
  DROP CONSTRAINT IF EXISTS fk_hc_exception_actions_operator;

ALTER TABLE public.hc_settlement_items
  DROP CONSTRAINT IF EXISTS fk_hc_settlement_items_settlement,
  DROP CONSTRAINT IF EXISTS fk_hc_settlement_items_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_settlement_items_execution_record;

ALTER TABLE public.hc_payments
  DROP CONSTRAINT IF EXISTS fk_hc_payments_settlement,
  DROP CONSTRAINT IF EXISTS fk_hc_payments_payer;

ALTER TABLE public.hc_refunds
  DROP CONSTRAINT IF EXISTS fk_hc_refunds_payment,
  DROP CONSTRAINT IF EXISTS fk_hc_refunds_settlement,
  DROP CONSTRAINT IF EXISTS fk_hc_refunds_created_by;

ALTER TABLE public.hc_ledgers
  DROP CONSTRAINT IF EXISTS fk_hc_ledgers_settlement,
  DROP CONSTRAINT IF EXISTS fk_hc_ledgers_created_by;

ALTER TABLE public.hc_archive_files
  DROP CONSTRAINT IF EXISTS fk_hc_archive_files_ledger,
  DROP CONSTRAINT IF EXISTS fk_hc_archive_files_created_by;

ALTER TABLE public.hc_consent_records
  DROP CONSTRAINT IF EXISTS fk_hc_consent_records_elder,
  DROP CONSTRAINT IF EXISTS fk_hc_consent_records_granted_by;

ALTER TABLE public.hc_dispatch_assignments
  DROP CONSTRAINT IF EXISTS fk_hc_dispatch_assignments_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_dispatch_assignments_worker,
  DROP CONSTRAINT IF EXISTS fk_hc_dispatch_assignments_created_by,
  DROP CONSTRAINT IF EXISTS fk_hc_dispatch_assignments_updated_by;

ALTER TABLE public.hc_worker_locations
  DROP CONSTRAINT IF EXISTS fk_hc_worker_locations_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_worker_locations_worker;

ALTER TABLE public.hc_work_order_confirmations
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_confirmations_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_work_order_confirmations_confirmed_by;

ALTER TABLE public.hc_state_transitions
  DROP CONSTRAINT IF EXISTS fk_hc_state_transitions_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_state_transitions_triggered_by;

ALTER TABLE public.hc_audit_logs
  DROP CONSTRAINT IF EXISTS fk_hc_audit_logs_work_order,
  DROP CONSTRAINT IF EXISTS fk_hc_audit_logs_actor;

ALTER TABLE public.hc_sensitive_access_logs
  DROP CONSTRAINT IF EXISTS fk_hc_sensitive_access_logs_accessor;

-- hc_work_order_events foreign keys
ALTER TABLE public.hc_work_order_events
  ADD CONSTRAINT fk_hc_work_order_events_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_work_order_events_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_work_order_events_operator
    FOREIGN KEY (operator_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;

-- hc_work_order_exceptions foreign keys
ALTER TABLE public.hc_work_order_exceptions
  ADD CONSTRAINT fk_hc_work_order_exceptions_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_work_order_exceptions_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_work_order_exceptions_created_by
    FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_work_order_exceptions_handled_by
    FOREIGN KEY (handled_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_evidence_files foreign keys
ALTER TABLE public.hc_evidence_files
  ADD CONSTRAINT fk_hc_evidence_files_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_evidence_files_uploader
    FOREIGN KEY (uploader_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;

-- hc_worker_qualifications foreign keys
ALTER TABLE public.hc_worker_qualifications
  ADD CONSTRAINT fk_hc_worker_qualifications_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_worker_qualifications_reviewed_by
    FOREIGN KEY (reviewed_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_settlements foreign keys
ALTER TABLE public.hc_settlements
  ADD CONSTRAINT fk_hc_settlements_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT;

-- hc_acceptances foreign keys
ALTER TABLE public.hc_acceptances
  ADD CONSTRAINT fk_hc_acceptances_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_acceptances_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_acceptances_accepted_by
    FOREIGN KEY (accepted_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_acceptance_issues foreign keys
ALTER TABLE public.hc_acceptance_issues
  ADD CONSTRAINT fk_hc_acceptance_issues_acceptance
    FOREIGN KEY (acceptance_id) REFERENCES public.hc_acceptances(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_acceptance_issues_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_acceptance_issues_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_acceptance_issues_reporter
    FOREIGN KEY (reporter_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_acceptance_issues_handler
    FOREIGN KEY (handler_id) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_complaints foreign keys
ALTER TABLE public.hc_complaints
  ADD CONSTRAINT fk_hc_complaints_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_complaints_acceptance_issue
    FOREIGN KEY (acceptance_issue_id) REFERENCES public.hc_acceptance_issues(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_complaints_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_complaints_complainant
    FOREIGN KEY (complainant_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_complaints_handler
    FOREIGN KEY (handler_id) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_exception_actions foreign keys
ALTER TABLE public.hc_exception_actions
  ADD CONSTRAINT fk_hc_exception_actions_exception
    FOREIGN KEY (exception_id) REFERENCES public.hc_work_order_exceptions(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_exception_actions_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_exception_actions_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_exception_actions_operator
    FOREIGN KEY (operator_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;

-- hc_settlement_items foreign keys
ALTER TABLE public.hc_settlement_items
  ADD CONSTRAINT fk_hc_settlement_items_settlement
    FOREIGN KEY (settlement_id) REFERENCES public.hc_settlements(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_settlement_items_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_settlement_items_execution_record
    FOREIGN KEY (execution_record_id) REFERENCES public.ec_care_records(id) ON DELETE SET NULL;

-- hc_payments foreign keys
ALTER TABLE public.hc_payments
  ADD CONSTRAINT fk_hc_payments_settlement
    FOREIGN KEY (settlement_id) REFERENCES public.hc_settlements(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_payments_payer
    FOREIGN KEY (payer_id) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_refunds foreign keys
ALTER TABLE public.hc_refunds
  ADD CONSTRAINT fk_hc_refunds_payment
    FOREIGN KEY (payment_id) REFERENCES public.hc_payments(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_refunds_settlement
    FOREIGN KEY (settlement_id) REFERENCES public.hc_settlements(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_refunds_created_by
    FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_ledgers foreign keys
ALTER TABLE public.hc_ledgers
  ADD CONSTRAINT fk_hc_ledgers_settlement
    FOREIGN KEY (settlement_id) REFERENCES public.hc_settlements(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_ledgers_created_by
    FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_archive_files foreign keys
ALTER TABLE public.hc_archive_files
  ADD CONSTRAINT fk_hc_archive_files_ledger
    FOREIGN KEY (ledger_id) REFERENCES public.hc_ledgers(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_archive_files_created_by
    FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- hc_consent_records foreign keys
ALTER TABLE public.hc_consent_records
  ADD CONSTRAINT fk_hc_consent_records_elder
    FOREIGN KEY (elder_id) REFERENCES public.ec_elders(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_consent_records_granted_by
    FOREIGN KEY (granted_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- Location distance phase 1 foreign keys
ALTER TABLE public.hc_dispatch_assignments
  ADD CONSTRAINT fk_hc_dispatch_assignments_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_dispatch_assignments_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_dispatch_assignments_created_by
    FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_dispatch_assignments_updated_by
    FOREIGN KEY (updated_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

ALTER TABLE public.hc_worker_locations
  ADD CONSTRAINT fk_hc_worker_locations_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_worker_locations_worker
    FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;

ALTER TABLE public.hc_work_order_confirmations
  ADD CONSTRAINT fk_hc_work_order_confirmations_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_work_order_confirmations_confirmed_by
    FOREIGN KEY (confirmed_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;

-- Audit extension tables foreign keys
ALTER TABLE public.hc_state_transitions
  ADD CONSTRAINT fk_hc_state_transitions_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
  ADD CONSTRAINT fk_hc_state_transitions_triggered_by
    FOREIGN KEY (triggered_by) REFERENCES public.ak_users(id) ON DELETE RESTRICT;

ALTER TABLE public.hc_audit_logs
  ADD CONSTRAINT fk_hc_audit_logs_work_order
    FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_hc_audit_logs_actor
    FOREIGN KEY (actor_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;

ALTER TABLE public.hc_sensitive_access_logs
  ADD CONSTRAINT fk_hc_sensitive_access_logs_accessor
    FOREIGN KEY (accessor_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;

-- ============================================================
-- Part 7: Seed Data - SLA Config
-- ============================================================

-- Phase 1 SLA configuration
-- Checkin radius: 50 meters (phase 1 final)
INSERT INTO public.sys_sla_config (id, config_key, config_value, value_type, scope_type, description)
VALUES
  ('sla_001', 'HOMECARE_CHECKIN_RADIUS_METERS', '50', 'integer', 'GLOBAL', '签到半径（一期50米）'),
  ('sla_002', 'HOMECARE_LOCATION_REFRESH_SECONDS', '30', 'integer', 'GLOBAL', '定位刷新间隔（秒）'),
  ('sla_003', 'HOMECARE_CHECKIN_MAX_PHOTO_COUNT', '3', 'integer', 'GLOBAL', '签到最大照片数'),
  ('sla_004', 'HOMECARE_CHECKIN_MAX_PHOTO_SIZE_MB', '5', 'integer', 'GLOBAL', '单张最大照片大小(MB)')
ON CONFLICT (id) DO NOTHING;

-- ============================================================
-- Part 8: Comments
-- ============================================================

COMMENT ON TABLE public.hc_work_order_events IS '居家服务工单事件表 - 业务时间线展示';
COMMENT ON TABLE public.hc_work_order_exceptions IS '居家服务工单异常表';
COMMENT ON TABLE public.hc_evidence_files IS '居家服务证据文件表 - 签到照片、异常图片等';
COMMENT ON TABLE public.hc_worker_qualifications IS '居家服务人员资质表';
COMMENT ON TABLE public.hc_settlements IS '居家服务结算表';
COMMENT ON TABLE public.hc_acceptances IS '居家服务确认表';
COMMENT ON TABLE public.hc_acceptance_issues IS '居家服务确认问题表';
COMMENT ON TABLE public.hc_complaints IS '居家服务投诉表';
COMMENT ON TABLE public.hc_exception_actions IS '居家服务异常操作表';
COMMENT ON TABLE public.hc_settlement_items IS '居家服务结算明细表';
COMMENT ON TABLE public.hc_payments IS '居家服务支付表';
COMMENT ON TABLE public.hc_refunds IS '居家服务退款表';
COMMENT ON TABLE public.hc_ledgers IS '居家服务账簿表';
COMMENT ON TABLE public.hc_archive_files IS '居家服务归档文件表';
COMMENT ON TABLE public.hc_consent_records IS '居家服务同意记录表';
COMMENT ON TABLE public.hc_dispatch_assignments IS '居家服务派单记录表 - 定位距离一期';
COMMENT ON TABLE public.hc_worker_locations IS '居家服务人员定位表 - 定位距离一期';
COMMENT ON TABLE public.hc_work_order_confirmations IS '居家服务工单确认表 - 定位距离一期';
COMMENT ON TABLE public.sys_sla_config IS '居家服务SLA配置表';
COMMENT ON TABLE public.hc_state_transitions IS '居家服务状态变迁表 - 审计';
COMMENT ON TABLE public.hc_audit_logs IS '居家服务操作审计表';
COMMENT ON TABLE public.hc_sensitive_access_logs IS '居家服务敏感访问日志表';

COMMENT ON COLUMN public.hc_evidence_files.upload_status IS '上传状态: TEMP/READY/BOUND/LOCKED/DELETED';
COMMENT ON COLUMN public.hc_evidence_files.bound_action IS '绑定动作: CHECKIN/CHECKOUT/EXCEPTION';
COMMENT ON COLUMN public.hc_worker_locations.location_scene IS '定位场景: ON_THE_WAY/CHECKIN_PRECHECK/CHECKIN/CHECKOUT';
COMMENT ON COLUMN public.hc_work_order_confirmations.confirmation_type IS '确认类型: ARRIVAL（二期扩展CHECKOUT）';
COMMENT ON COLUMN public.hc_work_order_confirmations.signature_url IS '二期电子签名图片URL（预留）';
COMMENT ON COLUMN public.hc_work_order_confirmations.signature_hash IS '二期电子签名哈希（预留）';

COMMIT;
