\q
--
-- PostgreSQL database dump
--

-- Dumped from database version 15.13
-- Dumped by pg_dump version 15.13

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- Name: vinn; Type: SCHEMA; Schema: -; Owner: postgres
--

CREATE SCHEMA vinn;


ALTER SCHEMA vinn OWNER TO postgres;

--
-- Name: admin_ref_add_user(text, text, text); Type: FUNCTION; Schema: vinn; Owner: postgres
--

CREATE FUNCTION vinn.admin_ref_add_user(ref_code text, actual_user_id text, source_type text DEFAULT 'bot'::text) RETURNS void
    LANGUAGE plpgsql
    AS $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM legacy.admin_ref WHERE value = ref_code) THEN
        RAISE EXCEPTION 'Admin referral code % not found', ref_code;
    END IF;

    IF NOT EXISTS (SELECT 1 FROM legacy.all_user WHERE user_id = actual_user_id) THEN
        RAISE EXCEPTION 'User % not found', actual_user_id;
    END IF;

    RAISE LOG 'User % registered via web admin referral code %', actual_user_id, ref_code;

    -- Update legacy fields (maintain old behavior)
    IF source_type = 'bot' THEN
        UPDATE legacy.admin_ref 
        SET 
            number = COALESCE(number, 0) + 1,
            "user" = CASE 
                WHEN "user" IS NULL OR "user" = '' THEN actual_user_id
                ELSE "user" || ',' || actual_user_id
            END
        WHERE value = ref_code;
    ELSIF source_type = 'web' THEN -- web
        UPDATE legacy.admin_ref 
        SET 
            number_web = COALESCE(number_web, 0) + 1,
            user_web = CASE 
                WHEN user_web IS NULL OR user_web = '' THEN actual_user_id
                ELSE user_web || ',' || actual_user_id
            END
        WHERE value = ref_code;
    ELSE
        RAISE EXCEPTION 'Invalid source type: %', source_type;
    END IF;
    
    -- Also add to normalized table
    INSERT INTO legacy.admin_ref_users (admin_ref_value, user_id, source) 
    VALUES (ref_code, actual_user_id, source_type) 
    ON CONFLICT (admin_ref_value, user_id, source) DO NOTHING;
END;
$$;


ALTER FUNCTION vinn.admin_ref_add_user(ref_code text, actual_user_id text, source_type text) OWNER TO postgres;

--
-- Name: schema_is(common.schematype); Type: FUNCTION; Schema: vinn; Owner: postgres
--

CREATE FUNCTION vinn.schema_is(_type common.schematype) RETURNS boolean
    LANGUAGE plpgsql
    AS $$
BEGIN
    IF 'inner'::SCHEMATYPE = _type THEN
       RETURN true;
    ELSE
       RETURN false;
    END IF;
END; $$;


ALTER FUNCTION vinn.schema_is(_type common.schematype) OWNER TO postgres;

--
-- Name: send_email(text, text, text); Type: FUNCTION; Schema: vinn; Owner: postgres
--

CREATE FUNCTION vinn.send_email(email text, subject text, message text) RETURNS void
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
DECLARE
    "sender" TEXT = 'info.vproxy.store@gmail.com';
    "password" TEXT = 'gaig pqmj jnnw zzwu';
BEGIN
    PERFORM smtp_client.send_email(
        "subject",        
        "message",
        true,                                 
        "sender",         
        ARRAY["email"],                         
        NULL::text[],                         
        NULL::text[],                         
        'smtp.gmail.com',                     
        465,                                  
        true,                                 
        "sender",         
        "password"                 
    );
END
$$;


ALTER FUNCTION vinn.send_email(email text, subject text, message text) OWNER TO postgres;

--
-- Name: signinup_tg(text, bigint, text, text, text, text); Type: FUNCTION; Schema: vinn; Owner: postgres
--

CREATE FUNCTION vinn.signinup_tg(_role text, tg_id bigint, tg_username text, tg_first_name text, tg_surname text, referral_id text) RETURNS void
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
DECLARE
  _existing_role NAME;
  _referral_is_user BOOLEAN;
  _reg_date DATE := CURRENT_DATE;
BEGIN
  -- Check if role already exists
  SELECT
    rolname
  FROM
    pg_authid
  WHERE
    rolname = tg_id::TEXT
  INTO
    _existing_role;

  IF _existing_role IS NULL THEN
      -- Create database role for the user
      EXECUTE format('CREATE ROLE "%s"; GRANT vgate_user TO "%s";', tg_id, tg_id);

      -- Insert into all_user table
      INSERT INTO legacy.all_user (
          user_id,
          reg_date,
          invited_by,
          pers_percent,
          lang,
          telegram_username,
          telegram_first_name,
          telegram_last_name,
          telegram_id
      ) VALUES (
          tg_id::TEXT,
          _reg_date,
          NULL,
          NULL,
          NULL,
          tg_username,
          tg_first_name,
          tg_surname,
          tg_id
      );

      -- Handle referral logic if referral_id is provided
      IF referral_id IS NOT NULL AND referral_id != '' THEN
          -- Check if referral_id is an existing user
          SELECT EXISTS (
              SELECT 1 FROM legacy.all_user WHERE user_id = referral_id
          ) INTO _referral_is_user;

          IF _referral_is_user THEN
              -- Referral ID is another user - set invited_by
              UPDATE legacy.all_user
              SET invited_by = referral_id
              WHERE user_id = tg_id::TEXT;
          ELSE
              -- Referral ID is admin ref link - update admin_ref table
              BEGIN
                  RAISE LOG 'Adding user to admin_ref_users: %', referral_id;
                  PERFORM vinn.admin_ref_add_user(
                      referral_id, 
                      tg_id::TEXT,
                      'bot'
                  );
              EXCEPTION WHEN OTHERS THEN
                  RAISE NOTICE 'Error: Failed to add user to admin_ref_users: %', SQLERRM;
              END;

              -- Also set invited_by for tracking
              UPDATE legacy.all_user
              SET invited_by = referral_id
              WHERE user_id = tg_id::TEXT;
          END IF;
      END IF;

      BEGIN
          PERFORM common.send_signup_notification(tg_id::TEXT, tg_username, 'bot');
      EXCEPTION WHEN OTHERS THEN
          RAISE LOG 'Failed to send signup notification: %', SQLERRM;
      END;
  ELSE
      -- User already exists, just update their Telegram info
      UPDATE legacy.all_user
      SET
          telegram_username = tg_username,
          telegram_first_name = tg_first_name,
          telegram_last_name = tg_surname,
          telegram_id = tg_id
      WHERE user_id = tg_id::TEXT;
  END IF;

EXCEPTION
    WHEN duplicate_object THEN
        -- Role already exists, just update user info
        UPDATE legacy.all_user
        SET
            telegram_username = tg_username,
            telegram_first_name = tg_first_name,
            telegram_last_name = tg_surname,
            telegram_id = tg_id
        WHERE user_id = tg_id::TEXT;
    WHEN others THEN
        RAISE LOG 'Unexpected error in signinup_tg: %', SQLERRM;
        RAISE EXCEPTION 'Unexpected error in signinup_tg';
END;
$$;


ALTER FUNCTION vinn.signinup_tg(_role text, tg_id bigint, tg_username text, tg_first_name text, tg_surname text, referral_id text) OWNER TO postgres;

--
-- Name: signup(text, text, text, text, text); Type: FUNCTION; Schema: vinn; Owner: postgres
--

CREATE FUNCTION vinn.signup(_role text, email text, username text, password text, referral_id text, OUT user_id text) RETURNS text
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
DECLARE
  _existing_role name;
  _scram_hash text;

  _gateway_schema text;
  _inner_schema text;
  rolename TEXT;
BEGIN
  RAISE LOG 'Inner signup attempt: %', username;

  SELECT current_schemas[1] FROM CURRENT_SCHEMAS(false) INTO _gateway_schema;
  SELECT current_schemas[2] FROM CURRENT_SCHEMAS(false) INTO _inner_schema;

  rolename = _gateway_schema || '_' || username;

  -- Check if the role already exists
  SELECT rolname INTO _existing_role
  FROM pg_authid
  WHERE rolname = rolename;

  IF _existing_role IS NOT NULL THEN
    RAISE LOG 'User % already exists in the system', username;
    RAISE sqlstate 'PT409' USING message = 'User already exists';
  END IF;

  _scram_hash = common.generate_scram_hash(password);

  RAISE LOG 'Creating role: % % % %', rolename, _scram_hash, _gateway_schema, username;

  -- Create the new PostgreSQL role with the SCRAM password
  BEGIN
    INSERT INTO legacy.all_user
      (user_id, reg_date, invited_by, pers_percent, lang, email, username, password)
    VALUES (rolename, now(), referral_id, NULL, NULL, email, username, _scram_hash)
    RETURNING all_user.user_id INTO signup.user_id;
  EXCEPTION
    WHEN unique_violation THEN
        RAISE LOG 'Signup error: Duplicate email % or username %', email, username;
        RAISE sqlstate 'PT409' USING message = 'User with this email or username already exists';
    WHEN foreign_key_violation THEN
        RAISE LOG 'Signup error: Invalid referral ID for user %', username;
        RAISE sqlstate 'PT400' USING message = 'Invalid referral ID provided';
    WHEN others THEN
        RAISE LOG 'Unexpected error in inner signup: %', SQLERRM;
        RAISE sqlstate 'PT500' USING message = 'Internal server error during signup';
  END;
END;
$$;


ALTER FUNCTION vinn.signup(_role text, email text, username text, password text, referral_id text, OUT user_id text) OWNER TO postgres;

SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: discount_tier; Type: TABLE; Schema: vinn; Owner: postgres
--

CREATE TABLE vinn.discount_tier (
    min_amount integer NOT NULL,
    discount double precision
)
INHERITS (common.created_at);


ALTER TABLE vinn.discount_tier OWNER TO postgres;

--
-- Name: storage; Type: TABLE; Schema: vinn; Owner: postgres
--

CREATE TABLE vinn.storage (
    dataimpulse_jwt text
)
INHERITS (common.created_at);


ALTER TABLE vinn.storage OWNER TO postgres;

--
-- Name: discount_tier created_at; Type: DEFAULT; Schema: vinn; Owner: postgres
--

ALTER TABLE ONLY vinn.discount_tier ALTER COLUMN created_at SET DEFAULT now();


--
-- Name: storage created_at; Type: DEFAULT; Schema: vinn; Owner: postgres
--

ALTER TABLE ONLY vinn.storage ALTER COLUMN created_at SET DEFAULT now();


--
-- Name: discount_tier discount_tier_pkey; Type: CONSTRAINT; Schema: vinn; Owner: postgres
--

ALTER TABLE ONLY vinn.discount_tier
    ADD CONSTRAINT discount_tier_pkey PRIMARY KEY (min_amount);


--
-- Name: SCHEMA vinn; Type: ACL; Schema: -; Owner: postgres
--

GRANT USAGE ON SCHEMA vinn TO anon;


--
-- Name: FUNCTION admin_ref_add_user(ref_code text, actual_user_id text, source_type text); Type: ACL; Schema: vinn; Owner: postgres
--

GRANT ALL ON FUNCTION vinn.admin_ref_add_user(ref_code text, actual_user_id text, source_type text) TO vproxy;


--
-- Name: FUNCTION schema_is(_type common.schematype); Type: ACL; Schema: vinn; Owner: postgres
--

GRANT ALL ON FUNCTION vinn.schema_is(_type common.schematype) TO vproxy;


--
-- Name: FUNCTION send_email(email text, subject text, message text); Type: ACL; Schema: vinn; Owner: postgres
--

GRANT ALL ON FUNCTION vinn.send_email(email text, subject text, message text) TO vproxy;


--
-- Name: FUNCTION signinup_tg(_role text, tg_id bigint, tg_username text, tg_first_name text, tg_surname text, referral_id text); Type: ACL; Schema: vinn; Owner: postgres
--

GRANT ALL ON FUNCTION vinn.signinup_tg(_role text, tg_id bigint, tg_username text, tg_first_name text, tg_surname text, referral_id text) TO vproxy;


--
-- Name: FUNCTION signup(_role text, email text, username text, password text, referral_id text, OUT user_id text); Type: ACL; Schema: vinn; Owner: postgres
--

GRANT ALL ON FUNCTION vinn.signup(_role text, email text, username text, password text, referral_id text, OUT user_id text) TO vproxy;


--
-- Name: TABLE discount_tier; Type: ACL; Schema: vinn; Owner: postgres
--

GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE vinn.discount_tier TO vproxy;


--
-- Name: TABLE storage; Type: ACL; Schema: vinn; Owner: postgres
--

GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE vinn.storage TO vproxy;
GRANT SELECT ON TABLE vinn.storage TO anon;


--
-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: vinn; Owner: postgres
--

ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA vinn GRANT SELECT,USAGE ON SEQUENCES  TO vproxy;


--
-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: vinn; Owner: postgres
--

ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA vinn GRANT ALL ON FUNCTIONS  TO vproxy;


--
-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: vinn; Owner: postgres
--

ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA vinn GRANT SELECT,INSERT,DELETE,UPDATE ON TABLES  TO vproxy;


--
-- PostgreSQL database dump complete
--

