CREATE EXTENSION IF NOT EXISTS pgcrypto;

CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TABLE IF NOT EXISTS users (
  user_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  username text NOT NULL UNIQUE,
  password_hash text NOT NULL,
  display_name text NOT NULL,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

DROP TRIGGER IF EXISTS users_set_updated_at ON users;
CREATE TRIGGER users_set_updated_at
BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION set_updated_at();

CREATE TABLE IF NOT EXISTS user_totp (
  user_id uuid PRIMARY KEY REFERENCES users(user_id) ON DELETE CASCADE,
  otp_secret text NOT NULL,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

DROP TRIGGER IF EXISTS user_totp_set_updated_at ON user_totp;
CREATE TRIGGER user_totp_set_updated_at
BEFORE UPDATE ON user_totp
FOR EACH ROW EXECUTE FUNCTION set_updated_at();

CREATE TABLE IF NOT EXISTS sessions (
  session_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id uuid NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
  expires_at timestamptz NOT NULL,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS sessions_user_id_idx ON sessions(user_id);
CREATE INDEX IF NOT EXISTS sessions_expires_at_idx ON sessions(expires_at);

DROP TRIGGER IF EXISTS sessions_set_updated_at ON sessions;
CREATE TRIGGER sessions_set_updated_at
BEFORE UPDATE ON sessions
FOR EACH ROW EXECUTE FUNCTION set_updated_at();

CREATE TABLE IF NOT EXISTS sites (
  site_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id uuid NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
  url text NOT NULL,
  alias text NOT NULL,
  certificate_issuer text,
  certificate_issued_at timestamptz,
  certificate_expires_at timestamptz,
  certificate_checked_at timestamptz,
  certificate_check_error text,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE (user_id, url)
);

ALTER TABLE sites
  ADD COLUMN IF NOT EXISTS certificate_issuer text,
  ADD COLUMN IF NOT EXISTS certificate_issued_at timestamptz,
  ADD COLUMN IF NOT EXISTS certificate_expires_at timestamptz,
  ADD COLUMN IF NOT EXISTS certificate_checked_at timestamptz,
  ADD COLUMN IF NOT EXISTS certificate_check_error text;

CREATE INDEX IF NOT EXISTS sites_user_id_idx ON sites(user_id);

DROP TRIGGER IF EXISTS sites_set_updated_at ON sites;
CREATE TRIGGER sites_set_updated_at
BEFORE UPDATE ON sites
FOR EACH ROW EXECUTE FUNCTION set_updated_at();

CREATE TABLE IF NOT EXISTS notification_methods (
  notification_method_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id uuid NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
  notification_type text NOT NULL CHECK (notification_type IN ('webhook', 'push')),
  alias text NOT NULL,
  url text,
  push_endpoint text,
  push_p256dh text,
  push_auth text,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS notification_methods_user_id_idx ON notification_methods(user_id);

DROP TRIGGER IF EXISTS notification_methods_set_updated_at ON notification_methods;
CREATE TRIGGER notification_methods_set_updated_at
BEFORE UPDATE ON notification_methods
FOR EACH ROW EXECUTE FUNCTION set_updated_at();

CREATE TABLE IF NOT EXISTS user_notification_settings (
  user_id uuid PRIMARY KEY REFERENCES users(user_id) ON DELETE CASCADE,
  webhook_message_template text,
  timezone text NOT NULL DEFAULT 'Asia/Tokyo',
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

ALTER TABLE user_notification_settings
  ADD COLUMN IF NOT EXISTS webhook_message_template text,
  ADD COLUMN IF NOT EXISTS timezone text NOT NULL DEFAULT 'Asia/Tokyo';

DROP TRIGGER IF EXISTS user_notification_settings_set_updated_at ON user_notification_settings;
CREATE TRIGGER user_notification_settings_set_updated_at
BEFORE UPDATE ON user_notification_settings
FOR EACH ROW EXECUTE FUNCTION set_updated_at();

CREATE TABLE IF NOT EXISTS site_alert_conditions (
  site_alert_condition_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  site_id uuid NOT NULL REFERENCES sites(site_id) ON DELETE CASCADE,
  condition_type text NOT NULL CHECK (condition_type IN ('expires_within_hours')),
  threshold_hours integer NOT NULL CHECK (threshold_hours > 0 AND threshold_hours <= 17520),
  webhook_method_ids uuid[] NOT NULL DEFAULT '{}',
  push_enabled boolean NOT NULL DEFAULT false,
  last_notified_certificate_expires_at timestamptz,
  last_notified_at timestamptz,
  last_notification_skipped_at timestamptz,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE (site_id, condition_type, threshold_hours)
);

ALTER TABLE site_alert_conditions
  ADD COLUMN IF NOT EXISTS last_notified_certificate_expires_at timestamptz,
  ADD COLUMN IF NOT EXISTS last_notified_at timestamptz,
  ADD COLUMN IF NOT EXISTS last_notification_skipped_at timestamptz;

CREATE INDEX IF NOT EXISTS site_alert_conditions_site_id_idx ON site_alert_conditions(site_id);

DROP TRIGGER IF EXISTS site_alert_conditions_set_updated_at ON site_alert_conditions;
CREATE TRIGGER site_alert_conditions_set_updated_at
BEFORE UPDATE ON site_alert_conditions
FOR EACH ROW EXECUTE FUNCTION set_updated_at();

CREATE TABLE IF NOT EXISTS alert_history (
  alert_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id uuid NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
  site_id uuid REFERENCES sites(site_id) ON DELETE SET NULL,
  alert_type text NOT NULL,
  content text NOT NULL,
  occurred_at timestamptz NOT NULL DEFAULT now(),
  read_at timestamptz,
  delivery_channels text[] NOT NULL DEFAULT ARRAY['app'],
  delivery_result jsonb NOT NULL DEFAULT '{}'::jsonb,
  dedupe_key text,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE (user_id, dedupe_key)
);

CREATE INDEX IF NOT EXISTS alert_history_user_id_idx ON alert_history(user_id);
CREATE INDEX IF NOT EXISTS alert_history_site_id_idx ON alert_history(site_id);
CREATE INDEX IF NOT EXISTS alert_history_occurred_at_idx ON alert_history(occurred_at);

DROP TRIGGER IF EXISTS alert_history_set_updated_at ON alert_history;
CREATE TRIGGER alert_history_set_updated_at
BEFORE UPDATE ON alert_history
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
