-- =====================================================
-- Member Communications Tracking
--
-- Records all communications with/about members:
-- emails sent, phone calls, notes, letters, meetings.
-- Communications are append-only for authenticated users.
-- Only service_role (admin) can delete.
-- Integrates with audit log via triggers.
-- =====================================================

CREATE TABLE IF NOT EXISTS public.member_communications (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  member_id uuid NOT NULL REFERENCES public.members(id) ON DELETE CASCADE,
  account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE,
  type text NOT NULL CHECK (type IN ('email', 'phone', 'letter', 'meeting', 'note', 'sms')),
  direction text NOT NULL DEFAULT 'outbound' CHECK (direction IN ('inbound', 'outbound', 'internal')),
  subject text CHECK (subject IS NULL OR length(subject) <= 500),
  body text CHECK (body IS NULL OR length(body) <= 50000),
  -- Email-specific fields
  email_to text,
  email_cc text,
  email_message_id text,
  -- Attachment references (Supabase Storage paths)
  attachment_paths text[] CHECK (attachment_paths IS NULL OR array_length(attachment_paths, 1) <= 10),
  -- Audit
  created_by uuid NOT NULL REFERENCES auth.users(id) ON DELETE SET NULL,
  created_at timestamptz NOT NULL DEFAULT now()
);

COMMENT ON TABLE public.member_communications IS
  'Communication log per member — emails, calls, notes, letters, meetings. Append-only for regular users.';

CREATE INDEX ix_member_comms_member
  ON public.member_communications(member_id, created_at DESC);
CREATE INDEX ix_member_comms_account
  ON public.member_communications(account_id, created_at DESC);
CREATE INDEX ix_member_comms_type
  ON public.member_communications(account_id, type);

ALTER TABLE public.member_communications ENABLE ROW LEVEL SECURITY;
REVOKE ALL ON public.member_communications FROM authenticated, service_role;
-- Append-only: authenticated users can SELECT + INSERT, not UPDATE/DELETE
GRANT SELECT, INSERT ON public.member_communications TO authenticated;
GRANT ALL ON public.member_communications TO service_role;

-- Read: must have a role on the account
CREATE POLICY member_comms_select
  ON public.member_communications FOR SELECT TO authenticated
  USING (public.has_role_on_account(account_id));

-- Insert: must have members.write permission
CREATE POLICY member_comms_insert
  ON public.member_communications FOR INSERT TO authenticated
  WITH CHECK (public.has_permission(auth.uid(), account_id, 'members.write'::public.app_permissions));

-- No UPDATE/DELETE policies for authenticated — communications are immutable
-- service_role can still delete via admin client when necessary

-- Auto-log to audit trail on communication INSERT
CREATE OR REPLACE FUNCTION public.trg_member_comm_audit_insert()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
  INSERT INTO public.member_audit_log (
    member_id, account_id, user_id, action, metadata
  ) VALUES (
    NEW.member_id,
    NEW.account_id,
    NEW.created_by,
    'communication_logged',
    jsonb_build_object(
      'communication_id', NEW.id,
      'type', NEW.type,
      'direction', NEW.direction,
      'subject', NEW.subject
    )
  );
  RETURN NEW;
EXCEPTION WHEN OTHERS THEN
  -- Audit failure should not block the insert
  RETURN NEW;
END;
$$;

CREATE TRIGGER trg_member_comms_audit_insert
  AFTER INSERT ON public.member_communications
  FOR EACH ROW
  EXECUTE FUNCTION public.trg_member_comm_audit_insert();

-- Safe delete function for admin use — logs before deleting
CREATE OR REPLACE FUNCTION public.delete_member_communication(
  p_communication_id uuid,
  p_account_id uuid
)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
  v_comm record;
BEGIN
  -- Verify caller has access
  IF NOT public.has_permission(auth.uid(), p_account_id, 'members.write'::public.app_permissions) THEN
    RAISE EXCEPTION 'Access denied' USING ERRCODE = '42501';
  END IF;

  -- Fetch the communication for audit
  SELECT * INTO v_comm
  FROM public.member_communications
  WHERE id = p_communication_id AND account_id = p_account_id;

  IF v_comm IS NULL THEN
    RAISE EXCEPTION 'Communication not found' USING ERRCODE = 'P0002';
  END IF;

  -- Log deletion to audit trail
  INSERT INTO public.member_audit_log (
    member_id, account_id, user_id, action, metadata
  ) VALUES (
    v_comm.member_id,
    v_comm.account_id,
    auth.uid(),
    'communication_logged',
    jsonb_build_object(
      'deleted_communication_id', v_comm.id,
      'type', v_comm.type,
      'direction', v_comm.direction,
      'subject', v_comm.subject,
      'action_detail', 'deleted'
    )
  );

  -- Delete via service_role context (SECURITY DEFINER bypasses RLS)
  DELETE FROM public.member_communications
  WHERE id = p_communication_id AND account_id = p_account_id;
END;
$$;

GRANT EXECUTE ON FUNCTION public.delete_member_communication(uuid, uuid)
  TO authenticated, service_role;
