-- Extension UUID v7 (préférer pg_uuidv7 si dispo, sinon fallback Node).
-- Note: pg_uuidv7 peut ne pas être disponible dans toutes les distributions Postgres 16.
-- Cette migration tentera de créer l'extension, et si elle échoue, le fallback sera
-- la génération côté Node via uuid@9+ (cf. ADR-0002).
DO $$
BEGIN
  CREATE EXTENSION IF NOT EXISTS pg_uuidv7;
EXCEPTION
  WHEN OTHERS THEN
    -- Extension non disponible, on créera une fonction fallback
    CREATE OR REPLACE FUNCTION uuidv7() RETURNS uuid AS $func$
    BEGIN
      RAISE EXCEPTION 'uuidv7() requires pg_uuidv7 extension or Node-side generation';
    END;
    $func$ LANGUAGE plpgsql;
END $$;
--> statement-breakpoint
-- Trigger updated_at (bump à chaque UPDATE sur agents)
CREATE OR REPLACE FUNCTION set_updated_at() RETURNS trigger AS $$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;
--> statement-breakpoint
CREATE TABLE "agents" (
	"id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
	"name" text NOT NULL,
	"display_name" text NOT NULL,
	"role" text NOT NULL,
	"created_at" timestamp with time zone DEFAULT now() NOT NULL,
	"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
	CONSTRAINT "agents_name_unique" UNIQUE("name"),
	CONSTRAINT "agents_name_check" CHECK ("agents"."name" ~ '^[a-z0-9][a-z0-9-]{0,63}$'),
	CONSTRAINT "agents_display_name_check" CHECK (length("agents"."display_name") BETWEEN 1 AND 128),
	CONSTRAINT "agents_role_check" CHECK ("agents"."role" IN ('admin', 'agent'))
);
--> statement-breakpoint
CREATE TRIGGER agents_set_updated_at
  BEFORE UPDATE ON agents
  FOR EACH ROW EXECUTE FUNCTION set_updated_at();
--> statement-breakpoint
CREATE TABLE "api_tokens" (
	"id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
	"agent_id" uuid NOT NULL,
	"hash_argon2id" text NOT NULL,
	"prefix" text NOT NULL,
	"scopes" jsonb DEFAULT '{}'::jsonb NOT NULL,
	"status" text DEFAULT 'active' NOT NULL,
	"expires_at" timestamp with time zone,
	"created_at" timestamp with time zone DEFAULT now() NOT NULL,
	"revoked_at" timestamp with time zone,
	CONSTRAINT "api_tokens_prefix_unique" UNIQUE("prefix"),
	CONSTRAINT "api_tokens_prefix_check" CHECK ("api_tokens"."prefix" ~ '^ah_live_[a-zA-Z0-9]{4}$'),
	CONSTRAINT "api_tokens_status_check" CHECK ("api_tokens"."status" IN ('active', 'rotating', 'revoked')),
	CONSTRAINT "api_tokens_revoked_at_check" CHECK ("api_tokens"."revoked_at" IS NULL OR "api_tokens"."status" = 'revoked'),
	CONSTRAINT "api_tokens_expires_at_check" CHECK ("api_tokens"."expires_at" IS NULL OR "api_tokens"."expires_at" > "api_tokens"."created_at")
);
--> statement-breakpoint
CREATE TABLE "audit_events" (
	"id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
	"type" text NOT NULL,
	"agent_id" uuid,
	"payload_hash" "bytea" NOT NULL,
	"ts" timestamp with time zone DEFAULT now() NOT NULL,
	CONSTRAINT "audit_events_type_check" CHECK ("audit_events"."type" IN (
        'login',
        'token-issued',
        'token-rotated',
        'token-revoked',
        'jwt-issued',
        'agent-created',
        'agent-deleted',
        'room-created',
        'room-deleted',
        'message-sent'
      )),
	CONSTRAINT "audit_events_payload_hash_check" CHECK (length("audit_events"."payload_hash") = 32)
);
--> statement-breakpoint
CREATE TABLE "messages" (
	"id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
	"room_id" uuid NOT NULL,
	"author_agent_id" uuid NOT NULL,
	"body" text NOT NULL,
	"created_at" timestamp with time zone DEFAULT now() NOT NULL,
	CONSTRAINT "messages_body_check" CHECK (length("messages"."body") BETWEEN 1 AND 16384)
);
--> statement-breakpoint
CREATE TABLE "room_members" (
	"room_id" uuid NOT NULL,
	"agent_id" uuid NOT NULL,
	"joined_at" timestamp with time zone DEFAULT now() NOT NULL,
	CONSTRAINT "room_members_room_id_agent_id_pk" PRIMARY KEY("room_id","agent_id")
);
--> statement-breakpoint
CREATE TABLE "rooms" (
	"id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
	"slug" text NOT NULL,
	"name" text NOT NULL,
	"created_by" uuid,
	"created_at" timestamp with time zone DEFAULT now() NOT NULL,
	CONSTRAINT "rooms_slug_unique" UNIQUE("slug"),
	CONSTRAINT "rooms_slug_check" CHECK ("rooms"."slug" ~ '^[a-z0-9][a-z0-9-]{0,63}$'),
	CONSTRAINT "rooms_name_check" CHECK (length("rooms"."name") BETWEEN 1 AND 128)
);
--> statement-breakpoint
ALTER TABLE "api_tokens" ADD CONSTRAINT "api_tokens_agent_id_agents_id_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."agents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "audit_events" ADD CONSTRAINT "audit_events_agent_id_agents_id_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."agents"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "messages" ADD CONSTRAINT "messages_room_id_rooms_id_fk" FOREIGN KEY ("room_id") REFERENCES "public"."rooms"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "messages" ADD CONSTRAINT "messages_author_agent_id_agents_id_fk" FOREIGN KEY ("author_agent_id") REFERENCES "public"."agents"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "room_members" ADD CONSTRAINT "room_members_room_id_rooms_id_fk" FOREIGN KEY ("room_id") REFERENCES "public"."rooms"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "room_members" ADD CONSTRAINT "room_members_agent_id_agents_id_fk" FOREIGN KEY ("agent_id") REFERENCES "public"."agents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "rooms" ADD CONSTRAINT "rooms_created_by_agents_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."agents"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "agents_role_idx" ON "agents" USING btree ("role");--> statement-breakpoint
CREATE INDEX "api_tokens_agent_id_idx" ON "api_tokens" USING btree ("agent_id");--> statement-breakpoint
CREATE INDEX "api_tokens_active_prefix_idx" ON "api_tokens" USING btree ("prefix") WHERE "api_tokens"."status" = 'active';--> statement-breakpoint
CREATE INDEX "audit_events_ts_idx" ON "audit_events" USING btree ("ts");--> statement-breakpoint
CREATE INDEX "audit_events_type_ts_idx" ON "audit_events" USING btree ("type","ts");--> statement-breakpoint
CREATE INDEX "audit_events_agent_ts_idx" ON "audit_events" USING btree ("agent_id","ts") WHERE "audit_events"."agent_id" IS NOT NULL;--> statement-breakpoint
CREATE INDEX "messages_room_created_at_idx" ON "messages" USING btree ("room_id","created_at" DESC,"id" DESC);--> statement-breakpoint
CREATE INDEX "room_members_agent_id_idx" ON "room_members" USING btree ("agent_id");