-- CreateSchema
CREATE SCHEMA IF NOT EXISTS "public";

-- CreateEnum
DO $$ BEGIN
  CREATE TYPE "service_location" AS ENUM ('office', 'delivery');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  CREATE TYPE "service_status" AS ENUM ('pending', 'accepted', 'denied', 'active', 'cancelled', 'completed', 'self_booked');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

-- CreateTable
CREATE TABLE IF NOT EXISTS "chats" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "user_id" UUID NOT NULL,
    "professional_id" UUID NOT NULL,
    "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "chats_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "cities" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "region_id" UUID NOT NULL,
    "name" VARCHAR(255) NOT NULL,
    "latitude" DECIMAL(10,7),
    "longitude" DECIMAL(10,7),

    CONSTRAINT "cities_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "comments" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "author_id" UUID NOT NULL,
    "destination_id" UUID NOT NULL,
    "service_id" UUID,
    "content" TEXT,
    "score" SMALLINT NOT NULL,
    "is_from_user" BOOLEAN NOT NULL DEFAULT true,
    "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "comments_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "countries" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "name" VARCHAR(255) NOT NULL,

    CONSTRAINT "countries_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "messages" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "chat_id" UUID NOT NULL,
    "sender_id" UUID NOT NULL,
    "content" TEXT NOT NULL,
    "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "messages_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "payment_methods" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "professional_id" UUID NOT NULL,
    "nequi" BOOLEAN DEFAULT false,
    "datafono" BOOLEAN DEFAULT false,
    "transferencia" BOOLEAN DEFAULT false,

    CONSTRAINT "payment_methods_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "professionals" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "user_id" UUID NOT NULL,
    "identification" VARCHAR(50),
    "address" TEXT,
    "additional_address" TEXT,
    "profession" VARCHAR(255),
    "rate" DECIMAL(10,2),
    "rate_preferences" TEXT,
    "location_preferences" VARCHAR(20) DEFAULT 'office',
    "banner_picture" TEXT,
    "identification_picture" TEXT,
    "certificate_picture" TEXT,
    "latitude" DECIMAL(10,7),
    "longitude" DECIMAL(10,7),
    "average_score" DECIMAL(3,2) DEFAULT 0,
    "is_active" BOOLEAN DEFAULT true,
    "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "professionals_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "professions" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "name" VARCHAR(255) NOT NULL,

    CONSTRAINT "professions_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "regions" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "country_id" UUID NOT NULL,
    "name" VARCHAR(255) NOT NULL,

    CONSTRAINT "regions_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "reputations" (
    "user_id" UUID NOT NULL,
    "total" INTEGER NOT NULL DEFAULT 0,
    "average" DECIMAL(3,2) NOT NULL DEFAULT 0,
    "total_pro" INTEGER NOT NULL DEFAULT 0,
    "average_pro" DECIMAL(3,2) NOT NULL DEFAULT 0,
    "updated_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "reputations_pkey" PRIMARY KEY ("user_id")
);

CREATE TABLE IF NOT EXISTS "schedules" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "professional_id" UUID NOT NULL,
    "day_of_week" SMALLINT NOT NULL,
    "enabled" BOOLEAN DEFAULT false,
    "continuous_day" BOOLEAN DEFAULT false,
    "range1_hour1" TIME(6),
    "range1_hour2" TIME(6),
    "range2_hour1" TIME(6),
    "range2_hour2" TIME(6),

    CONSTRAINT "schedules_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "services" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "professional_id" UUID NOT NULL,
    "user_id" UUID NOT NULL,
    "address" TEXT,
    "additional_address" TEXT,
    "latitude" DECIMAL(10,7),
    "longitude" DECIMAL(10,7),
    "day" DATE NOT NULL,
    "description" TEXT,
    "rate" DECIMAL(10,2),
    "range1_hour1" TIME(6),
    "range1_hour2" TIME(6),
    "status" "service_status" NOT NULL DEFAULT 'pending',
    "location_preference" "service_location" DEFAULT 'office',
    "professional_scored" BOOLEAN DEFAULT false,
    "user_scored" BOOLEAN DEFAULT false,
    "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "services_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "settings" (
    "key" VARCHAR(100) NOT NULL,
    "value" JSONB NOT NULL,
    "updated_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "settings_pkey" PRIMARY KEY ("key")
);

CREATE TABLE IF NOT EXISTS "specializations" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "professional_id" UUID NOT NULL,
    "name" VARCHAR(255) NOT NULL,
    "picture" TEXT,

    CONSTRAINT "specializations_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "suggestions" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "name" VARCHAR(255),
    "message" TEXT NOT NULL,
    "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "suggestions_pkey" PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "users" (
    "id" UUID NOT NULL DEFAULT uuid_generate_v4(),
    "email" VARCHAR(255),
    "phone" VARCHAR(20),
    "password_hash" VARCHAR(255),
    "name" VARCHAR(255) NOT NULL,
    "nickname" VARCHAR(100),
    "city" VARCHAR(100),
    "picture" TEXT,
    "birthday" DATE,
    "gender" VARCHAR(20),
    "pro_state" SMALLINT NOT NULL DEFAULT 0,
    "fcm_token" TEXT,
    "is_phone_verified" BOOLEAN DEFAULT false,
    "is_email_verified" BOOLEAN DEFAULT false,
    "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE INDEX IF NOT EXISTS "idx_chats_professional_id" ON "chats"("professional_id");
CREATE INDEX IF NOT EXISTS "idx_chats_user_id" ON "chats"("user_id");
CREATE UNIQUE INDEX IF NOT EXISTS "chats_user_id_professional_id_key" ON "chats"("user_id", "professional_id");
CREATE INDEX IF NOT EXISTS "idx_cities_region_id" ON "cities"("region_id");
CREATE INDEX IF NOT EXISTS "idx_comments_author_id" ON "comments"("author_id");
CREATE INDEX IF NOT EXISTS "idx_comments_destination_id" ON "comments"("destination_id");
CREATE INDEX IF NOT EXISTS "idx_comments_service_id" ON "comments"("service_id");
CREATE UNIQUE INDEX IF NOT EXISTS "countries_name_key" ON "countries"("name");
CREATE INDEX IF NOT EXISTS "idx_messages_chat_id" ON "messages"("chat_id");
CREATE INDEX IF NOT EXISTS "idx_messages_created_at" ON "messages"("created_at");
CREATE UNIQUE INDEX IF NOT EXISTS "payment_methods_professional_id_key" ON "payment_methods"("professional_id");
CREATE UNIQUE INDEX IF NOT EXISTS "professionals_user_id_key" ON "professionals"("user_id");
CREATE INDEX IF NOT EXISTS "idx_professionals_user_id" ON "professionals"("user_id");
CREATE UNIQUE INDEX IF NOT EXISTS "professions_name_key" ON "professions"("name");
CREATE INDEX IF NOT EXISTS "idx_regions_country_id" ON "regions"("country_id");
CREATE INDEX IF NOT EXISTS "idx_schedules_professional_id" ON "schedules"("professional_id");
CREATE UNIQUE INDEX IF NOT EXISTS "schedules_professional_id_day_of_week_key" ON "schedules"("professional_id", "day_of_week");
CREATE INDEX IF NOT EXISTS "idx_services_day" ON "services"("day");
CREATE INDEX IF NOT EXISTS "idx_services_professional_id" ON "services"("professional_id");
CREATE INDEX IF NOT EXISTS "idx_services_status" ON "services"("status");
CREATE INDEX IF NOT EXISTS "idx_services_user_id" ON "services"("user_id");
CREATE INDEX IF NOT EXISTS "idx_specializations_professional_id" ON "specializations"("professional_id");
CREATE UNIQUE INDEX IF NOT EXISTS "users_email_key" ON "users"("email");
CREATE UNIQUE INDEX IF NOT EXISTS "users_phone_key" ON "users"("phone");

-- AddForeignKey (idempotent via DO blocks)
DO $$ BEGIN
  ALTER TABLE "chats" ADD CONSTRAINT "chats_professional_id_fkey" FOREIGN KEY ("professional_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "chats" ADD CONSTRAINT "chats_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "cities" ADD CONSTRAINT "cities_region_id_fkey" FOREIGN KEY ("region_id") REFERENCES "regions"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "comments" ADD CONSTRAINT "comments_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "comments" ADD CONSTRAINT "comments_destination_id_fkey" FOREIGN KEY ("destination_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "comments" ADD CONSTRAINT "comments_service_id_fkey" FOREIGN KEY ("service_id") REFERENCES "services"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "messages" ADD CONSTRAINT "messages_chat_id_fkey" FOREIGN KEY ("chat_id") REFERENCES "chats"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "messages" ADD CONSTRAINT "messages_sender_id_fkey" FOREIGN KEY ("sender_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "payment_methods" ADD CONSTRAINT "payment_methods_professional_id_fkey" FOREIGN KEY ("professional_id") REFERENCES "professionals"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "professionals" ADD CONSTRAINT "professionals_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "regions" ADD CONSTRAINT "regions_country_id_fkey" FOREIGN KEY ("country_id") REFERENCES "countries"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "reputations" ADD CONSTRAINT "reputations_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "schedules" ADD CONSTRAINT "schedules_professional_id_fkey" FOREIGN KEY ("professional_id") REFERENCES "professionals"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "services" ADD CONSTRAINT "services_professional_id_fkey" FOREIGN KEY ("professional_id") REFERENCES "professionals"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "services" ADD CONSTRAINT "services_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE "specializations" ADD CONSTRAINT "specializations_professional_id_fkey" FOREIGN KEY ("professional_id") REFERENCES "professionals"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;

-- Trigger: update reputation on comment insert/update
CREATE OR REPLACE FUNCTION update_reputation()
RETURNS TRIGGER AS $$
BEGIN
  UPDATE reputations
  SET
    total = (SELECT COUNT(*) FROM comments WHERE destination_id = NEW.destination_id AND is_from_user = false),
    average = (SELECT COALESCE(AVG(score), 0) FROM comments WHERE destination_id = NEW.destination_id AND is_from_user = false),
    total_pro = (SELECT COUNT(*) FROM comments WHERE destination_id = NEW.destination_id AND is_from_user = true),
    average_pro = (SELECT COALESCE(AVG(score), 0) FROM comments WHERE destination_id = NEW.destination_id AND is_from_user = true),
    updated_at = NOW()
  WHERE user_id = NEW.destination_id;

  IF NOT FOUND THEN
    INSERT INTO reputations (user_id, total, average, total_pro, average_pro, updated_at)
    VALUES (
      NEW.destination_id,
      (SELECT COUNT(*) FROM comments WHERE destination_id = NEW.destination_id AND is_from_user = false),
      (SELECT COALESCE(AVG(score), 0) FROM comments WHERE destination_id = NEW.destination_id AND is_from_user = false),
      (SELECT COUNT(*) FROM comments WHERE destination_id = NEW.destination_id AND is_from_user = true),
      (SELECT COALESCE(AVG(score), 0) FROM comments WHERE destination_id = NEW.destination_id AND is_from_user = true),
      NOW()
    );
  END IF;

  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE TRIGGER trg_update_reputation
  AFTER INSERT OR UPDATE ON comments
  FOR EACH ROW
  EXECUTE FUNCTION update_reputation();
