CREATE TABLE IF NOT EXISTS users (
    id UUID PRIMARY KEY,
    email TEXT NOT NULL DEFAULT '',
    name TEXT NOT NULL DEFAULT '',
    status TEXT NOT NULL DEFAULT 'active',
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

INSERT INTO users (id, email, name, status)
VALUES ('00000000-0000-0000-0000-000000000001', 'local@example.test', 'Local User', 'active')
ON CONFLICT (id) DO NOTHING;
ALTER TABLE users ALTER COLUMN id TYPE UUID USING NULLIF(id::text, '')::uuid;
ALTER TABLE users ADD COLUMN IF NOT EXISTS region TEXT NOT NULL DEFAULT 'china';
ALTER TABLE users ADD COLUMN IF NOT EXISTS phone_country_code TEXT NOT NULL DEFAULT '';
ALTER TABLE users ADD COLUMN IF NOT EXISTS phone TEXT NOT NULL DEFAULT '';
ALTER TABLE users ADD COLUMN IF NOT EXISTS avatar_url TEXT NOT NULL DEFAULT '';
ALTER TABLE users ADD COLUMN IF NOT EXISTS password_hash TEXT NOT NULL DEFAULT '';
ALTER TABLE users ADD COLUMN IF NOT EXISTS wechat_open_id TEXT NOT NULL DEFAULT '';
ALTER TABLE users ADD COLUMN IF NOT EXISTS wechat_union_id TEXT NOT NULL DEFAULT '';
ALTER TABLE users ADD COLUMN IF NOT EXISTS google_subject TEXT NOT NULL DEFAULT '';
ALTER TABLE users ADD COLUMN IF NOT EXISTS phone_verified_at TIMESTAMPTZ;
ALTER TABLE users ADD COLUMN IF NOT EXISTS email_verified_at TIMESTAMPTZ;
ALTER TABLE users ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMPTZ;
CREATE UNIQUE INDEX IF NOT EXISTS users_phone_unique_idx ON users(phone_country_code, phone) WHERE phone <> '';
CREATE UNIQUE INDEX IF NOT EXISTS users_email_unique_idx ON users(LOWER(email)) WHERE email <> '';
CREATE UNIQUE INDEX IF NOT EXISTS users_google_subject_unique_idx ON users(google_subject) WHERE google_subject <> '';
CREATE UNIQUE INDEX IF NOT EXISTS users_wechat_union_id_unique_idx ON users(wechat_union_id) WHERE wechat_union_id <> '';
CREATE UNIQUE INDEX IF NOT EXISTS users_wechat_open_id_unique_idx ON users(wechat_open_id) WHERE wechat_open_id <> '' AND wechat_union_id = '';

CREATE TABLE IF NOT EXISTS auth_verification_codes (
    id TEXT PRIMARY KEY,
    region TEXT NOT NULL,
    channel TEXT NOT NULL,
    target TEXT NOT NULL,
    purpose TEXT NOT NULL,
    code_hash TEXT NOT NULL,
    attempts INTEGER NOT NULL DEFAULT 0,
    expires_at TIMESTAMPTZ NOT NULL,
    consumed_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS auth_codes_target_idx ON auth_verification_codes(region, channel, target, purpose, created_at DESC);

CREATE TABLE IF NOT EXISTS projects (
    id TEXT PRIMARY KEY,
    user_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001'::uuid,
    title TEXT NOT NULL,
    brief TEXT NOT NULL,
    status TEXT NOT NULL,
    thumbnail TEXT NOT NULL,
    canvas TEXT NOT NULL DEFAULT '',
    version TEXT NOT NULL DEFAULT '',
    snapshot_id TEXT NOT NULL DEFAULT '',
    last_thread_id TEXT NOT NULL DEFAULT '',
    viewport_x DOUBLE PRECISION NOT NULL DEFAULT 0,
    viewport_y DOUBLE PRECISION NOT NULL DEFAULT 0,
    viewport_k DOUBLE PRECISION NOT NULL DEFAULT 1,
    updated_at TIMESTAMPTZ NOT NULL
);

ALTER TABLE projects ADD COLUMN IF NOT EXISTS user_id UUID;
ALTER TABLE projects ALTER COLUMN user_id DROP DEFAULT;
ALTER TABLE projects ALTER COLUMN user_id TYPE UUID USING NULLIF(user_id::text, '')::uuid;
UPDATE projects SET user_id = '00000000-0000-0000-0000-000000000001'::uuid WHERE user_id IS NULL;
ALTER TABLE projects ALTER COLUMN user_id SET DEFAULT '00000000-0000-0000-0000-000000000001'::uuid;
ALTER TABLE projects ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE projects ADD COLUMN IF NOT EXISTS canvas TEXT NOT NULL DEFAULT '';
ALTER TABLE projects ADD COLUMN IF NOT EXISTS version TEXT NOT NULL DEFAULT '';
ALTER TABLE projects ADD COLUMN IF NOT EXISTS snapshot_id TEXT NOT NULL DEFAULT '';
ALTER TABLE projects ADD COLUMN IF NOT EXISTS last_thread_id TEXT NOT NULL DEFAULT '';
CREATE INDEX IF NOT EXISTS projects_user_updated_idx ON projects(user_id, updated_at DESC);

CREATE TABLE IF NOT EXISTS canvas_nodes (
    id TEXT PRIMARY KEY,
    project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    user_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001'::uuid,
    node_type TEXT NOT NULL,
    title TEXT NOT NULL,
    x DOUBLE PRECISION NOT NULL,
    y DOUBLE PRECISION NOT NULL,
    width DOUBLE PRECISION NOT NULL,
    height DOUBLE PRECISION NOT NULL,
    content TEXT NOT NULL,
    tone TEXT NOT NULL,
    status TEXT NOT NULL,
    sort_order INTEGER NOT NULL DEFAULT 0,
    parent_id TEXT NOT NULL DEFAULT '',
    layer_role TEXT NOT NULL DEFAULT '',
    font_size DOUBLE PRECISION NOT NULL DEFAULT 0,
    font_family TEXT NOT NULL DEFAULT '',
    font_weight TEXT NOT NULL DEFAULT '',
    color TEXT NOT NULL DEFAULT '',
    text_align TEXT NOT NULL DEFAULT '',
    line_height DOUBLE PRECISION NOT NULL DEFAULT 0,
    letter_spacing DOUBLE PRECISION NOT NULL DEFAULT 0,
    text_decoration TEXT NOT NULL DEFAULT '',
    text_transform TEXT NOT NULL DEFAULT '',
    opacity DOUBLE PRECISION NOT NULL DEFAULT 0,
    fill_color TEXT NOT NULL DEFAULT '',
    stroke_color TEXT NOT NULL DEFAULT '',
    stroke_width DOUBLE PRECISION NOT NULL DEFAULT 0,
    stroke_style TEXT NOT NULL DEFAULT '',
    flip_x BOOLEAN NOT NULL DEFAULT FALSE,
    flip_y BOOLEAN NOT NULL DEFAULT FALSE,
    rotation DOUBLE PRECISION NOT NULL DEFAULT 0
);

ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS user_id UUID;
ALTER TABLE canvas_nodes ALTER COLUMN user_id DROP DEFAULT;
ALTER TABLE canvas_nodes ALTER COLUMN user_id TYPE UUID USING NULLIF(user_id::text, '')::uuid;
UPDATE canvas_nodes
SET user_id = COALESCE((SELECT p.user_id FROM projects p WHERE p.id = canvas_nodes.project_id), '00000000-0000-0000-0000-000000000001'::uuid)
WHERE user_id IS NULL;
ALTER TABLE canvas_nodes ALTER COLUMN user_id SET DEFAULT '00000000-0000-0000-0000-000000000001'::uuid;
ALTER TABLE canvas_nodes ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS sort_order INTEGER NOT NULL DEFAULT 0;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS parent_id TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS layer_role TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS font_size DOUBLE PRECISION NOT NULL DEFAULT 0;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS font_family TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS font_weight TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS color TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS text_align TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS line_height DOUBLE PRECISION NOT NULL DEFAULT 0;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS letter_spacing DOUBLE PRECISION NOT NULL DEFAULT 0;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS text_decoration TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS text_transform TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS opacity DOUBLE PRECISION NOT NULL DEFAULT 0;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS fill_color TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS stroke_color TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS stroke_width DOUBLE PRECISION NOT NULL DEFAULT 0;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS stroke_style TEXT NOT NULL DEFAULT '';
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS flip_x BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS flip_y BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE canvas_nodes ADD COLUMN IF NOT EXISTS rotation DOUBLE PRECISION NOT NULL DEFAULT 0;

CREATE INDEX IF NOT EXISTS canvas_nodes_project_id_idx ON canvas_nodes(project_id);
CREATE INDEX IF NOT EXISTS canvas_nodes_user_project_idx ON canvas_nodes(user_id, project_id);

CREATE TABLE IF NOT EXISTS mockup_blobs (
    data_id TEXT PRIMARY KEY,
    width INTEGER NOT NULL,
    height INTEGER NOT NULL,
    data BYTEA NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS canvas_connections (
    id TEXT PRIMARY KEY,
    project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    user_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001'::uuid,
    from_node_id TEXT NOT NULL,
    to_node_id TEXT NOT NULL
);

ALTER TABLE canvas_connections ADD COLUMN IF NOT EXISTS user_id UUID;
ALTER TABLE canvas_connections ALTER COLUMN user_id DROP DEFAULT;
ALTER TABLE canvas_connections ALTER COLUMN user_id TYPE UUID USING NULLIF(user_id::text, '')::uuid;
UPDATE canvas_connections
SET user_id = COALESCE((SELECT p.user_id FROM projects p WHERE p.id = canvas_connections.project_id), '00000000-0000-0000-0000-000000000001'::uuid)
WHERE user_id IS NULL;
ALTER TABLE canvas_connections ALTER COLUMN user_id SET DEFAULT '00000000-0000-0000-0000-000000000001'::uuid;
ALTER TABLE canvas_connections ALTER COLUMN user_id SET NOT NULL;
CREATE INDEX IF NOT EXISTS canvas_connections_project_id_idx ON canvas_connections(project_id);
CREATE INDEX IF NOT EXISTS canvas_connections_user_project_idx ON canvas_connections(user_id, project_id);

CREATE TABLE IF NOT EXISTS canvas_snapshots (
    id TEXT PRIMARY KEY,
    project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    user_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001'::uuid,
    version TEXT NOT NULL,
    canvas TEXT NOT NULL,
    viewport_json JSONB NOT NULL,
    nodes_json JSONB NOT NULL,
    connections_json JSONB NOT NULL,
    created_at TIMESTAMPTZ NOT NULL
);

ALTER TABLE canvas_snapshots ALTER COLUMN user_id DROP DEFAULT;
ALTER TABLE canvas_snapshots ALTER COLUMN user_id TYPE UUID USING NULLIF(user_id::text, '')::uuid;
UPDATE canvas_snapshots SET user_id = '00000000-0000-0000-0000-000000000001'::uuid WHERE user_id IS NULL;
ALTER TABLE canvas_snapshots ALTER COLUMN user_id SET DEFAULT '00000000-0000-0000-0000-000000000001'::uuid;
ALTER TABLE canvas_snapshots ALTER COLUMN user_id SET NOT NULL;
CREATE INDEX IF NOT EXISTS canvas_snapshots_project_version_idx ON canvas_snapshots(user_id, project_id, created_at DESC);

CREATE TABLE IF NOT EXISTS agent_messages (
    id TEXT PRIMARY KEY,
    project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    user_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001'::uuid,
    role TEXT NOT NULL,
    message_type TEXT NOT NULL DEFAULT '',
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    thread_id TEXT NOT NULL DEFAULT '',
    action_id TEXT NOT NULL DEFAULT '',
    step_id TEXT NOT NULL DEFAULT '',
    tool_call_id TEXT NOT NULL DEFAULT '',
    name TEXT NOT NULL DEFAULT '',
    tool_hint TEXT NOT NULL DEFAULT '',
    status TEXT NOT NULL DEFAULT '',
    created_at TIMESTAMPTZ NOT NULL
);

ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS user_id UUID;
ALTER TABLE agent_messages ALTER COLUMN user_id DROP DEFAULT;
ALTER TABLE agent_messages ALTER COLUMN user_id TYPE UUID USING NULLIF(user_id::text, '')::uuid;
UPDATE agent_messages
SET user_id = COALESCE((SELECT p.user_id FROM projects p WHERE p.id = agent_messages.project_id), '00000000-0000-0000-0000-000000000001'::uuid)
WHERE user_id IS NULL;
ALTER TABLE agent_messages ALTER COLUMN user_id SET DEFAULT '00000000-0000-0000-0000-000000000001'::uuid;
ALTER TABLE agent_messages ALTER COLUMN user_id SET NOT NULL;
ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS message_type TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS thread_id TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS action_id TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS step_id TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS tool_call_id TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS tool_hint TEXT NOT NULL DEFAULT '';
ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS status TEXT NOT NULL DEFAULT '';

CREATE INDEX IF NOT EXISTS agent_messages_project_id_idx ON agent_messages(project_id);
CREATE INDEX IF NOT EXISTS agent_messages_user_project_idx ON agent_messages(user_id, project_id);

CREATE TABLE IF NOT EXISTS outbox_events (
    id TEXT PRIMARY KEY,
    user_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000001'::uuid,
    aggregate_type TEXT NOT NULL,
    aggregate_id TEXT NOT NULL,
    event_type TEXT NOT NULL,
    thread_id TEXT NOT NULL DEFAULT '',
    payload_json JSONB NOT NULL,
    status TEXT NOT NULL DEFAULT 'pending',
    published_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

ALTER TABLE outbox_events ALTER COLUMN user_id DROP DEFAULT;
ALTER TABLE outbox_events ALTER COLUMN user_id TYPE UUID USING NULLIF(user_id::text, '')::uuid;
UPDATE outbox_events SET user_id = '00000000-0000-0000-0000-000000000001'::uuid WHERE user_id IS NULL;
ALTER TABLE outbox_events ALTER COLUMN user_id SET DEFAULT '00000000-0000-0000-0000-000000000001'::uuid;
ALTER TABLE outbox_events ALTER COLUMN user_id SET NOT NULL;
CREATE INDEX IF NOT EXISTS outbox_events_status_created_idx ON outbox_events(status, created_at);
CREATE INDEX IF NOT EXISTS outbox_events_project_idx ON outbox_events(aggregate_type, aggregate_id, created_at);
