-- Meshkee CMS — location reference tree (country → province → city)

CREATE TYPE city_level AS ENUM ('country', 'province', 'city');

CREATE TABLE cities (
  id            BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  parent_id     BIGINT,
  level         city_level NOT NULL,
  name_fa       VARCHAR(255) NOT NULL,
  name_en       VARCHAR(255) NOT NULL,
  landline_code VARCHAR(10),
  slug          VARCHAR(100) NOT NULL,
  sort_order    INTEGER NOT NULL DEFAULT 0,
  is_active     BOOLEAN NOT NULL DEFAULT TRUE,
  created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT cities_slug_unique UNIQUE (slug),
  CONSTRAINT cities_parent_id_fkey
    FOREIGN KEY (parent_id) REFERENCES cities (id) ON DELETE CASCADE,
  CONSTRAINT cities_slug_format CHECK (slug ~ '^[a-z0-9]+(?:-[a-z0-9]+)*$'),
  CONSTRAINT cities_name_fa_nonempty CHECK (char_length(trim(name_fa)) > 0),
  CONSTRAINT cities_name_en_nonempty CHECK (char_length(trim(name_en)) > 0),
  CONSTRAINT cities_landline_code_nonempty_optional CHECK (
    landline_code IS NULL OR char_length(trim(landline_code)) > 0
  ),
  CONSTRAINT cities_country_root CHECK (
    (level = 'country' AND parent_id IS NULL)
    OR (level <> 'country' AND parent_id IS NOT NULL)
  )
);

CREATE INDEX idx_cities_parent_id ON cities (parent_id);
CREATE INDEX idx_cities_level ON cities (level);
CREATE INDEX idx_cities_level_parent ON cities (level, parent_id, sort_order);
CREATE INDEX idx_cities_active ON cities (is_active) WHERE is_active = TRUE;

CREATE TRIGGER cities_set_updated_at
  BEFORE UPDATE ON cities
  FOR EACH ROW
  EXECUTE FUNCTION set_updated_at();

CREATE OR REPLACE FUNCTION cities_validate_parent_level()
RETURNS TRIGGER AS $$
DECLARE
  parent_level city_level;
BEGIN
  IF NEW.level = 'country' THEN
    RETURN NEW;
  END IF;

  SELECT level INTO parent_level FROM cities WHERE id = NEW.parent_id;

  IF NOT FOUND THEN
    RAISE EXCEPTION 'parent city not found';
  END IF;

  IF NEW.level = 'province' AND parent_level <> 'country' THEN
    RAISE EXCEPTION 'province parent must be a country';
  END IF;

  IF NEW.level = 'city' AND parent_level <> 'province' THEN
    RAISE EXCEPTION 'city parent must be a province';
  END IF;

  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER cities_validate_parent_level
  BEFORE INSERT OR UPDATE ON cities
  FOR EACH ROW
  EXECUTE FUNCTION cities_validate_parent_level();
