BEGIN;

ALTER TABLE public.ml_user_addresses
  ADD COLUMN IF NOT EXISTS latitude DOUBLE PRECISION,
  ADD COLUMN IF NOT EXISTS longitude DOUBLE PRECISION,
  ADD COLUMN IF NOT EXISTS coordinate_type TEXT NOT NULL DEFAULT 'gcj02';

CREATE TABLE IF NOT EXISTS public.hss_service_orders (
  id TEXT PRIMARY KEY,
  order_no TEXT NOT NULL UNIQUE,
  user_id UUID NOT NULL,
  service_id TEXT NOT NULL,
  service_name TEXT NOT NULL,
  service_snapshot_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  service_address_id UUID,
  address_snapshot_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  recipient_name TEXT NOT NULL DEFAULT '',
  recipient_phone TEXT NOT NULL DEFAULT '',
  contact_name TEXT NOT NULL DEFAULT '',
  contact_phone TEXT NOT NULL DEFAULT '',
  appointment_time TIMESTAMPTZ,
  remark TEXT NOT NULL DEFAULT '',
  status TEXT NOT NULL DEFAULT 'created',
  current_assignment_id TEXT NOT NULL DEFAULT '',
  current_staff_id UUID,
  accepted_at TIMESTAMPTZ,
  departed_at TIMESTAMPTZ,
  arrived_at TIMESTAMPTZ,
  service_started_at TIMESTAMPTZ,
  completed_at TIMESTAMPTZ,
  pending_acceptance_at TIMESTAMPTZ,
  accepted_by_user_at TIMESTAMPTZ,
  reviewed_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  deleted_at TIMESTAMPTZ,
  deleted_by UUID,
  CONSTRAINT chk_hss_service_orders_status CHECK (
    status IN (
      'created', 'paid', 'assigned', 'accepted', 'rejected', 'departed', 'arrived',
      'in_service', 'completed', 'pending_acceptance', 'accepted_by_user',
      'reviewed', 'settled', 'cancelled', 'exception'
    )
  )
);

CREATE TABLE IF NOT EXISTS public.hss_service_assignments (
  id TEXT PRIMARY KEY,
  order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
  staff_id UUID NOT NULL REFERENCES public.ml_delivery_staff(id) ON DELETE RESTRICT,
  station_id UUID REFERENCES public.ml_delivery_stations(id) ON DELETE SET NULL,
  status TEXT NOT NULL DEFAULT 'assigned',
  assigned_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  accepted_at TIMESTAMPTZ,
  rejected_at TIMESTAMPTZ,
  reject_reason TEXT NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  CONSTRAINT chk_hss_service_assignments_status CHECK (
    status IN ('assigned', 'accepted', 'rejected', 'departed', 'arrived', 'in_service', 'pending_acceptance', 'completed', 'cancelled', 'exception')
  )
);

CREATE TABLE IF NOT EXISTS public.hss_service_execution_records (
  id TEXT PRIMARY KEY,
  order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
  assignment_id TEXT NOT NULL REFERENCES public.hss_service_assignments(id) ON DELETE CASCADE,
  checkin_time TIMESTAMPTZ,
  checkin_latitude DOUBLE PRECISION,
  checkin_longitude DOUBLE PRECISION,
  checkin_address TEXT NOT NULL DEFAULT '',
  service_started_at TIMESTAMPTZ,
  service_finished_at TIMESTAMPTZ,
  actual_duration_minutes INTEGER NOT NULL DEFAULT 0,
  service_items_json JSONB NOT NULL DEFAULT '[]'::jsonb,
  summary TEXT NOT NULL DEFAULT '',
  remark TEXT NOT NULL DEFAULT '',
  track_points_json JSONB NOT NULL DEFAULT '[]'::jsonb,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS public.hss_service_evidence_files (
  id TEXT PRIMARY KEY,
  order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
  execution_record_id TEXT REFERENCES public.hss_service_execution_records(id) ON DELETE CASCADE,
  phase TEXT NOT NULL DEFAULT 'service',
  file_type TEXT NOT NULL DEFAULT 'image',
  storage_path TEXT NOT NULL DEFAULT '',
  file_url TEXT NOT NULL DEFAULT '',
  latitude DOUBLE PRECISION,
  longitude DOUBLE PRECISION,
  captured_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS public.hss_service_order_status_logs (
  id TEXT PRIMARY KEY,
  order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
  from_status TEXT NOT NULL DEFAULT '',
  to_status TEXT NOT NULL,
  operator_id UUID,
  operator_role TEXT NOT NULL DEFAULT '',
  remark TEXT NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS public.hss_service_reviews (
  id TEXT PRIMARY KEY,
  order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
  user_id UUID NOT NULL,
  rating INTEGER NOT NULL DEFAULT 5,
  tags_json JSONB NOT NULL DEFAULT '[]'::jsonb,
  content TEXT NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_hss_service_orders_user_status
  ON public.hss_service_orders(user_id, status)
  WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_hss_service_orders_staff_status
  ON public.hss_service_orders(current_staff_id, status)
  WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_hss_service_assignments_staff_status
  ON public.hss_service_assignments(staff_id, status);

CREATE INDEX IF NOT EXISTS idx_hss_service_execution_records_order
  ON public.hss_service_execution_records(order_id);

CREATE INDEX IF NOT EXISTS idx_hss_service_evidence_files_order
  ON public.hss_service_evidence_files(order_id);

CREATE INDEX IF NOT EXISTS idx_hss_service_logs_order_created
  ON public.hss_service_order_status_logs(order_id, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_hss_service_reviews_order
  ON public.hss_service_reviews(order_id);

CREATE OR REPLACE FUNCTION public.tg_hss_set_updated_at()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$;

DROP TRIGGER IF EXISTS trg_hss_service_orders_updated_at ON public.hss_service_orders;
CREATE TRIGGER trg_hss_service_orders_updated_at
BEFORE UPDATE ON public.hss_service_orders
FOR EACH ROW
EXECUTE FUNCTION public.tg_hss_set_updated_at();

DROP TRIGGER IF EXISTS trg_hss_service_assignments_updated_at ON public.hss_service_assignments;
CREATE TRIGGER trg_hss_service_assignments_updated_at
BEFORE UPDATE ON public.hss_service_assignments
FOR EACH ROW
EXECUTE FUNCTION public.tg_hss_set_updated_at();

DROP TRIGGER IF EXISTS trg_hss_service_execution_records_updated_at ON public.hss_service_execution_records;
CREATE TRIGGER trg_hss_service_execution_records_updated_at
BEFORE UPDATE ON public.hss_service_execution_records
FOR EACH ROW
EXECUTE FUNCTION public.tg_hss_set_updated_at();

ALTER TABLE public.hss_service_orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_assignments ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_execution_records ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_evidence_files ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_order_status_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_reviews ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS hss_service_orders_user_select ON public.hss_service_orders;
CREATE POLICY hss_service_orders_user_select
  ON public.hss_service_orders
  FOR SELECT
  TO authenticated
  USING (
    deleted_at IS NULL AND (
      user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
      OR current_staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL)
    )
  );

DROP POLICY IF EXISTS hss_service_orders_user_insert ON public.hss_service_orders;
CREATE POLICY hss_service_orders_user_insert
  ON public.hss_service_orders
  FOR INSERT
  TO authenticated
  WITH CHECK (user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()));

DROP POLICY IF EXISTS hss_service_orders_user_update ON public.hss_service_orders;
CREATE POLICY hss_service_orders_user_update
  ON public.hss_service_orders
  FOR UPDATE
  TO authenticated
  USING (
    deleted_at IS NULL AND (
      user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
      OR current_staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL)
    )
  )
  WITH CHECK (
    deleted_at IS NULL AND (
      user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
      OR current_staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL)
    )
  );

DROP POLICY IF EXISTS hss_service_assignments_staff_select ON public.hss_service_assignments;
CREATE POLICY hss_service_assignments_staff_select
  ON public.hss_service_assignments
  FOR SELECT
  TO authenticated
  USING (staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL));

DROP POLICY IF EXISTS hss_service_assignments_staff_update ON public.hss_service_assignments;
CREATE POLICY hss_service_assignments_staff_update
  ON public.hss_service_assignments
  FOR UPDATE
  TO authenticated
  USING (staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL))
  WITH CHECK (staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL));

DROP POLICY IF EXISTS hss_service_assignments_staff_insert ON public.hss_service_assignments;
CREATE POLICY hss_service_assignments_staff_insert
  ON public.hss_service_assignments
  FOR INSERT
  TO authenticated
  WITH CHECK (staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL));

DROP POLICY IF EXISTS hss_service_execution_records_order_access ON public.hss_service_execution_records;
CREATE POLICY hss_service_execution_records_order_access
  ON public.hss_service_execution_records
  FOR ALL
  TO authenticated
  USING (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL))
  WITH CHECK (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL));

DROP POLICY IF EXISTS hss_service_evidence_files_order_access ON public.hss_service_evidence_files;
CREATE POLICY hss_service_evidence_files_order_access
  ON public.hss_service_evidence_files
  FOR ALL
  TO authenticated
  USING (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL))
  WITH CHECK (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL));

DROP POLICY IF EXISTS hss_service_order_status_logs_order_access ON public.hss_service_order_status_logs;
CREATE POLICY hss_service_order_status_logs_order_access
  ON public.hss_service_order_status_logs
  FOR ALL
  TO authenticated
  USING (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL))
  WITH CHECK (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL));

DROP POLICY IF EXISTS hss_service_reviews_order_access ON public.hss_service_reviews;
CREATE POLICY hss_service_reviews_order_access
  ON public.hss_service_reviews
  FOR ALL
  TO authenticated
  USING (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL))
  WITH CHECK (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL));

COMMENT ON TABLE public.hss_service_orders IS '居家上门服务订单主表';
COMMENT ON TABLE public.hss_service_assignments IS '居家上门服务派单表';
COMMENT ON TABLE public.hss_service_execution_records IS '居家上门服务执行记录表';
COMMENT ON TABLE public.hss_service_evidence_files IS '居家上门服务证据文件表';
COMMENT ON TABLE public.hss_service_order_status_logs IS '居家上门服务状态日志表';
COMMENT ON TABLE public.hss_service_reviews IS '居家上门服务评价表';

COMMIT;