-- Meshkee CMS — RBAC, content tables, media

-- ---------------------------------------------------------------------------
-- enums
-- ---------------------------------------------------------------------------
CREATE TYPE content_status AS ENUM ('draft', 'published', 'archived');
CREATE TYPE media_type AS ENUM ('image', 'video');
CREATE TYPE media_entity_type AS ENUM ('product', 'blog', 'portfolio');

-- ---------------------------------------------------------------------------
-- permissions (RBAC)
-- ---------------------------------------------------------------------------
CREATE TABLE permissions (
  id          BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  name        VARCHAR(100) NOT NULL,
  slug        VARCHAR(100) NOT NULL,
  group_name  VARCHAR(50)  NOT NULL,
  description TEXT,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT permissions_slug_unique UNIQUE (slug)
);

CREATE TABLE roles (
  id          BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  name        VARCHAR(100) NOT NULL,
  slug        VARCHAR(100) NOT NULL,
  description TEXT,
  is_system   BOOLEAN NOT NULL DEFAULT TRUE,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT roles_slug_unique UNIQUE (slug)
);

CREATE TABLE role_permissions (
  role_id       BIGINT NOT NULL,
  permission_id BIGINT NOT NULL,
  created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  PRIMARY KEY (role_id, permission_id),
  CONSTRAINT role_permissions_role_id_fkey
    FOREIGN KEY (role_id) REFERENCES roles (id) ON DELETE CASCADE,
  CONSTRAINT role_permissions_permission_id_fkey
    FOREIGN KEY (permission_id) REFERENCES permissions (id) ON DELETE CASCADE
);

CREATE TABLE user_roles (
  id         BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  user_id    BIGINT NOT NULL,
  role_id    BIGINT NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT user_roles_user_role_unique UNIQUE (user_id, role_id),
  CONSTRAINT user_roles_user_id_fkey
    FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
  CONSTRAINT user_roles_role_id_fkey
    FOREIGN KEY (role_id) REFERENCES roles (id) ON DELETE CASCADE
);

CREATE INDEX idx_user_roles_user_id ON user_roles (user_id);
CREATE INDEX idx_role_permissions_permission_id ON role_permissions (permission_id);

CREATE TRIGGER roles_set_updated_at
  BEFORE UPDATE ON roles
  FOR EACH ROW
  EXECUTE FUNCTION set_updated_at();

-- ---------------------------------------------------------------------------
-- media (images & videos, scoped per business)
-- ---------------------------------------------------------------------------
CREATE TABLE media (
  id                  BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  business_id         BIGINT NOT NULL,
  uploaded_by         BIGINT,
  media_type          media_type NOT NULL,
  storage_disk        VARCHAR(50) NOT NULL DEFAULT 'local',
  storage_path        TEXT NOT NULL,
  public_url          TEXT NOT NULL,
  file_name           VARCHAR(255) NOT NULL,
  original_file_name  VARCHAR(255) NOT NULL,
  mime_type           VARCHAR(100) NOT NULL,
  file_size_bytes     BIGINT NOT NULL,
  width               INTEGER,
  height              INTEGER,
  duration_seconds    NUMERIC(10, 2),
  alt_text            VARCHAR(255),
  caption             TEXT,
  metadata            JSONB NOT NULL DEFAULT '{}',
  created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT media_business_id_fkey
    FOREIGN KEY (business_id) REFERENCES businesses (id) ON DELETE CASCADE,
  CONSTRAINT media_uploaded_by_fkey
    FOREIGN KEY (uploaded_by) REFERENCES users (id) ON DELETE SET NULL,
  CONSTRAINT media_file_size_positive CHECK (file_size_bytes > 0),
  CONSTRAINT media_image_dimensions CHECK (
    media_type <> 'image' OR (width IS NOT NULL AND height IS NOT NULL)
  ),
  CONSTRAINT media_video_duration CHECK (
    media_type <> 'video' OR duration_seconds IS NOT NULL
  )
);

CREATE INDEX idx_media_business_id ON media (business_id);
CREATE INDEX idx_media_business_type ON media (business_id, media_type);
CREATE INDEX idx_media_created_at ON media (business_id, created_at DESC);

CREATE TRIGGER media_set_updated_at
  BEFORE UPDATE ON media
  FOR EACH ROW
  EXECUTE FUNCTION set_updated_at();

-- ---------------------------------------------------------------------------
-- products
-- ---------------------------------------------------------------------------
CREATE TABLE products (
  id                BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  business_id       BIGINT NOT NULL,
  title             VARCHAR(255) NOT NULL,
  slug              VARCHAR(255) NOT NULL,
  description       TEXT,
  content           JSONB NOT NULL DEFAULT '{}',
  price             NUMERIC(12, 2),
  compare_at_price  NUMERIC(12, 2),
  sku               VARCHAR(100),
  stock_quantity    INTEGER,
  status            content_status NOT NULL DEFAULT 'draft',
  featured_media_id BIGINT,
  sort_order        INTEGER NOT NULL DEFAULT 0,
  published_at      TIMESTAMPTZ,
  metadata          JSONB NOT NULL DEFAULT '{}',
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT products_business_slug_unique UNIQUE (business_id, slug),
  CONSTRAINT products_business_id_fkey
    FOREIGN KEY (business_id) REFERENCES businesses (id) ON DELETE CASCADE,
  CONSTRAINT products_featured_media_id_fkey
    FOREIGN KEY (featured_media_id) REFERENCES media (id) ON DELETE SET NULL,
  CONSTRAINT products_price_non_negative CHECK (price IS NULL OR price >= 0),
  CONSTRAINT products_compare_price_non_negative CHECK (compare_at_price IS NULL OR compare_at_price >= 0),
  CONSTRAINT products_stock_non_negative CHECK (stock_quantity IS NULL OR stock_quantity >= 0)
);

CREATE INDEX idx_products_business_id ON products (business_id);
CREATE INDEX idx_products_business_status ON products (business_id, status);
CREATE INDEX idx_products_business_published ON products (business_id, published_at DESC);

CREATE TRIGGER products_set_updated_at
  BEFORE UPDATE ON products
  FOR EACH ROW
  EXECUTE FUNCTION set_updated_at();

-- ---------------------------------------------------------------------------
-- blogs
-- ---------------------------------------------------------------------------
CREATE TABLE blogs (
  id                BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  business_id       BIGINT NOT NULL,
  author_id         BIGINT,
  title             VARCHAR(255) NOT NULL,
  slug              VARCHAR(255) NOT NULL,
  excerpt           TEXT,
  content           JSONB NOT NULL DEFAULT '{}',
  status            content_status NOT NULL DEFAULT 'draft',
  featured_media_id BIGINT,
  published_at      TIMESTAMPTZ,
  metadata          JSONB NOT NULL DEFAULT '{}',
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT blogs_business_slug_unique UNIQUE (business_id, slug),
  CONSTRAINT blogs_business_id_fkey
    FOREIGN KEY (business_id) REFERENCES businesses (id) ON DELETE CASCADE,
  CONSTRAINT blogs_author_id_fkey
    FOREIGN KEY (author_id) REFERENCES users (id) ON DELETE SET NULL,
  CONSTRAINT blogs_featured_media_id_fkey
    FOREIGN KEY (featured_media_id) REFERENCES media (id) ON DELETE SET NULL
);

CREATE INDEX idx_blogs_business_id ON blogs (business_id);
CREATE INDEX idx_blogs_business_status ON blogs (business_id, status);
CREATE INDEX idx_blogs_business_published ON blogs (business_id, published_at DESC);

CREATE TRIGGER blogs_set_updated_at
  BEFORE UPDATE ON blogs
  FOR EACH ROW
  EXECUTE FUNCTION set_updated_at();

-- ---------------------------------------------------------------------------
-- portfolios
-- ---------------------------------------------------------------------------
CREATE TABLE portfolios (
  id                BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  business_id       BIGINT NOT NULL,
  title             VARCHAR(255) NOT NULL,
  slug              VARCHAR(255) NOT NULL,
  description       TEXT,
  content           JSONB NOT NULL DEFAULT '{}',
  client_name       VARCHAR(255),
  project_url       TEXT,
  status            content_status NOT NULL DEFAULT 'draft',
  featured_media_id BIGINT,
  sort_order        INTEGER NOT NULL DEFAULT 0,
  published_at      TIMESTAMPTZ,
  metadata          JSONB NOT NULL DEFAULT '{}',
  created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT portfolios_business_slug_unique UNIQUE (business_id, slug),
  CONSTRAINT portfolios_business_id_fkey
    FOREIGN KEY (business_id) REFERENCES businesses (id) ON DELETE CASCADE,
  CONSTRAINT portfolios_featured_media_id_fkey
    FOREIGN KEY (featured_media_id) REFERENCES media (id) ON DELETE SET NULL
);

CREATE INDEX idx_portfolios_business_id ON portfolios (business_id);
CREATE INDEX idx_portfolios_business_status ON portfolios (business_id, status);
CREATE INDEX idx_portfolios_business_published ON portfolios (business_id, published_at DESC);

CREATE TRIGGER portfolios_set_updated_at
  BEFORE UPDATE ON portfolios
  FOR EACH ROW
  EXECUTE FUNCTION set_updated_at();

-- ---------------------------------------------------------------------------
-- media attachments (galleries, inline images/videos on content)
-- ---------------------------------------------------------------------------
CREATE TABLE media_attachments (
  id          BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  business_id BIGINT NOT NULL,
  media_id    BIGINT NOT NULL,
  entity_type media_entity_type NOT NULL,
  entity_id   BIGINT NOT NULL,
  sort_order  INTEGER NOT NULL DEFAULT 0,
  is_featured BOOLEAN NOT NULL DEFAULT FALSE,
  created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  CONSTRAINT media_attachments_business_id_fkey
    FOREIGN KEY (business_id) REFERENCES businesses (id) ON DELETE CASCADE,
  CONSTRAINT media_attachments_media_id_fkey
    FOREIGN KEY (media_id) REFERENCES media (id) ON DELETE CASCADE,
  CONSTRAINT media_attachments_unique UNIQUE (media_id, entity_type, entity_id)
);

CREATE INDEX idx_media_attachments_entity
  ON media_attachments (business_id, entity_type, entity_id, sort_order);
CREATE INDEX idx_media_attachments_media_id ON media_attachments (media_id);

-- ---------------------------------------------------------------------------
-- seed: default permissions & roles
-- ---------------------------------------------------------------------------
INSERT INTO permissions (name, slug, group_name, description) VALUES
  ('View business',           'business.read',       'business',   'View business profile and settings'),
  ('Update business',         'business.update',     'business',   'Edit business profile and settings'),
  ('View domains',            'domains.read',        'domains',    'View connected domains'),
  ('Manage domains',          'domains.manage',      'domains',    'Add, edit, and remove domains'),
  ('View products',           'products.read',       'products',   'View products'),
  ('Create products',         'products.create',     'products',   'Create products'),
  ('Update products',         'products.update',     'products',   'Edit products'),
  ('Delete products',         'products.delete',     'products',   'Delete products'),
  ('Publish products',        'products.publish',    'products',   'Publish and unpublish products'),
  ('View blogs',              'blogs.read',          'blogs',      'View blog posts'),
  ('Create blogs',            'blogs.create',        'blogs',      'Create blog posts'),
  ('Update blogs',            'blogs.update',        'blogs',      'Edit blog posts'),
  ('Delete blogs',            'blogs.delete',        'blogs',      'Delete blog posts'),
  ('Publish blogs',           'blogs.publish',       'blogs',      'Publish and unpublish blog posts'),
  ('View portfolios',         'portfolios.read',     'portfolios', 'View portfolio items'),
  ('Create portfolios',       'portfolios.create',   'portfolios', 'Create portfolio items'),
  ('Update portfolios',       'portfolios.update',   'portfolios', 'Edit portfolio items'),
  ('Delete portfolios',       'portfolios.delete',   'portfolios', 'Delete portfolio items'),
  ('Publish portfolios',      'portfolios.publish',  'portfolios', 'Publish and unpublish portfolio items'),
  ('View media',              'media.read',          'media',      'View uploaded media'),
  ('Upload media',            'media.create',        'media',      'Upload images and videos'),
  ('Update media',            'media.update',        'media',      'Edit media metadata'),
  ('Delete media',            'media.delete',        'media',      'Delete media files'),
  ('View users',              'users.read',          'users',      'View user accounts'),
  ('Manage users',            'users.manage',        'users',      'Create and manage user accounts'),
  ('Manage roles',            'roles.manage',        'users',      'Assign roles and permissions');

INSERT INTO roles (name, slug, description, is_system) VALUES
  ('Owner',         'owner',  'Full access to everything', TRUE),
  ('Administrator', 'admin',  'Manage content, media, and settings', TRUE),
  ('Editor',        'editor', 'Create and edit content', TRUE),
  ('Viewer',        'viewer', 'Read-only access', TRUE);

INSERT INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id
FROM roles r
CROSS JOIN permissions p
WHERE r.slug = 'owner';

INSERT INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id
FROM roles r
JOIN permissions p ON p.slug <> 'roles.manage'
WHERE r.slug = 'admin';

INSERT INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id
FROM roles r
JOIN permissions p ON p.slug IN (
  'business.read',
  'products.read', 'products.create', 'products.update', 'products.publish',
  'blogs.read', 'blogs.create', 'blogs.update', 'blogs.publish',
  'portfolios.read', 'portfolios.create', 'portfolios.update', 'portfolios.publish',
  'media.read', 'media.create', 'media.update'
)
WHERE r.slug = 'editor';

INSERT INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id
FROM roles r
JOIN permissions p ON p.slug IN (
  'business.read',
  'domains.read',
  'products.read',
  'blogs.read',
  'portfolios.read',
  'media.read'
)
WHERE r.slug = 'viewer';
