package db

import (
	"database/sql"
	"fmt"
)

const CurrentSchemaVersion = "2026-06-compat-baseline"

func (s *Store) migrate(conn *sql.DB, d dialect) error {
	statements := []string{}
	if d.name == "sqlite" {
		statements = append(statements,
			"PRAGMA busy_timeout = 5000",
			"PRAGMA journal_mode = WAL",
			"PRAGMA foreign_keys = ON",
		)
	}
	statements = append(statements, schemaStatements(d)...)
	for _, statement := range statements {
		if _, err := conn.Exec(d.rebind(statement)); err != nil {
			return err
		}
	}
	return s.recordSchemaVersion(conn, d)
}

func schemaStatements(d dialect) []string {
	keyText := d.keyTextType()
	shortText := d.shortTextType()
	mediumText := d.mediumTextType()
	longText := d.longTextType()
	return []string{
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS schema_migrations (
			version VARCHAR(64) NOT NULL PRIMARY KEY,
			applied_at %s NOT NULL,
			description VARCHAR(255) NOT NULL DEFAULT ''
		)`, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS admin_users (
			id %s,
			username %s NOT NULL UNIQUE,
			password_hash %s NOT NULL,
			password_changed INTEGER NOT NULL DEFAULT 0,
			created_at %s NOT NULL,
			updated_at %s NOT NULL
		)`, d.idType(), keyText, shortText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS sessions (
			id %s,
			session_id %s NOT NULL UNIQUE,
			username %s NOT NULL,
			csrf %s NOT NULL,
			expires_at %s NOT NULL,
			created_at %s NOT NULL
		)`, d.idType(), keyText, keyText, shortText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS release_packages (
			id %s,
			product %s NOT NULL,
			version %s NOT NULL,
			platform %s NOT NULL,
			arch %s NOT NULL,
			file_name %s NOT NULL UNIQUE,
			url %s NOT NULL,
			sha256 %s NOT NULL,
			size_bytes BIGINT NOT NULL DEFAULT 0,
			enabled INTEGER NOT NULL DEFAULT 1,
			created_at %s NOT NULL,
			updated_at %s NOT NULL
		)`, d.idType(), keyText, keyText, keyText, keyText, keyText, mediumText, shortText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS release_notices (
			id %s,
			version %s NOT NULL UNIQUE,
			build %s NOT NULL DEFAULT '',
			channel %s NOT NULL DEFAULT 'stable',
			title %s NOT NULL DEFAULT '',
			message %s NOT NULL,
			release_notes %s NOT NULL,
			message_md %s NOT NULL,
			release_notes_md %s NOT NULL,
			download_url %s NOT NULL DEFAULT '',
			notice_file %s NOT NULL DEFAULT '',
			raw_json %s NOT NULL,
			published_at %s NOT NULL DEFAULT '',
			created_at %s NOT NULL,
			updated_at %s NOT NULL
		)`, d.idType(), keyText, shortText, shortText, mediumText, longText, longText, longText, longText, mediumText, keyText, longText, shortText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS release_notice_revisions (
			id %s,
			version %s NOT NULL,
			raw_json %s NOT NULL,
			note %s NOT NULL DEFAULT '',
			created_by %s NOT NULL DEFAULT '',
			created_at %s NOT NULL
		)`, d.idType(), keyText, longText, mediumText, keyText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_tickets (
			code %s PRIMARY KEY,
			title %s NOT NULL,
			type %s NOT NULL,
			severity %s NOT NULL,
			category %s NOT NULL DEFAULT '',
			priority %s NOT NULL DEFAULT '',
			contact %s NOT NULL DEFAULT '',
			body %s NOT NULL,
			status %s NOT NULL,
			status_detail %s NOT NULL DEFAULT '',
			public_reply %s NOT NULL,
			note %s NOT NULL,
			assignee %s NOT NULL DEFAULT '',
			handled_by %s NOT NULL DEFAULT '',
			due_at %s NOT NULL DEFAULT '',
			resolved_at %s NOT NULL DEFAULT '',
			archived_at %s NOT NULL DEFAULT '',
			sla_level %s NOT NULL DEFAULT '',
			source_channel %s NOT NULL DEFAULT '',
			risk_score INTEGER NOT NULL DEFAULT 0,
			resolution %s NOT NULL,
			attachment %s NOT NULL DEFAULT '',
			package_path %s NOT NULL DEFAULT '',
			encrypted_package_path %s NOT NULL DEFAULT '',
			package_sha256 %s NOT NULL DEFAULT '',
			plain_package_sha256 %s NOT NULL DEFAULT '',
			summary_text %s NOT NULL,
			included_files %s NOT NULL,
			mail_sent INTEGER NOT NULL DEFAULT 0,
			remote_addr %s NOT NULL DEFAULT '',
			tags %s NOT NULL,
			created_at %s NOT NULL,
			updated_at %s NOT NULL,
			last_activity_at %s NOT NULL
		)`, keyText, mediumText, keyText, keyText, keyText, keyText, mediumText, longText, keyText, mediumText, longText, longText, keyText, keyText, shortText, shortText, shortText, keyText, keyText, longText, mediumText, mediumText, mediumText, shortText, shortText, longText, longText, shortText, longText, shortText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_comments (
			id %s,
			feedback_code %s NOT NULL,
			author %s NOT NULL DEFAULT '',
			body %s NOT NULL,
			internal INTEGER NOT NULL DEFAULT 1,
			created_at %s NOT NULL
		)`, d.idType(), keyText, keyText, longText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_attachments (
			id %s,
			feedback_code %s NOT NULL,
			kind %s NOT NULL,
			path %s NOT NULL,
			file_name %s NOT NULL,
			sha256 %s NOT NULL DEFAULT '',
			size_bytes BIGINT NOT NULL DEFAULT 0,
			created_at %s NOT NULL
		)`, d.idType(), keyText, keyText, mediumText, mediumText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_events (
			id %s,
			feedback_code %s NOT NULL,
			event_type %s NOT NULL,
			actor %s NOT NULL DEFAULT '',
			from_value %s NOT NULL DEFAULT '',
			to_value %s NOT NULL DEFAULT '',
			message %s NOT NULL DEFAULT '',
			created_at %s NOT NULL
		)`, d.idType(), keyText, keyText, keyText, mediumText, mediumText, mediumText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_tags (
			feedback_code %s NOT NULL,
			tag %s NOT NULL,
			created_at %s NOT NULL,
			PRIMARY KEY (feedback_code, tag)
		)`, keyText, keyText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS mail_records (
			id %s,
			feedback_code %s NOT NULL DEFAULT '',
			kind %s NOT NULL DEFAULT '',
			status %s NOT NULL DEFAULT '',
			to_address %s NOT NULL DEFAULT '',
			subject %s NOT NULL DEFAULT '',
			plain_body %s NOT NULL,
			html_body %s NOT NULL,
			attachment_path %s NOT NULL DEFAULT '',
			attachment_name %s NOT NULL DEFAULT '',
			error_message %s NOT NULL,
			created_at %s NOT NULL,
			sent_at %s NOT NULL DEFAULT ''
		)`, d.idType(), keyText, keyText, keyText, mediumText, mediumText, longText, longText, mediumText, mediumText, longText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS source_categories (
			id %s,
			category_id %s NOT NULL UNIQUE,
			name %s NOT NULL,
			enabled INTEGER NOT NULL DEFAULT 1,
			ui_config %s NOT NULL,
			created_at %s NOT NULL,
			updated_at %s NOT NULL
		)`, d.idType(), keyText, shortText, longText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS source_endpoints (
			id %s,
			category_id %s NOT NULL,
			category_name %s NOT NULL,
			source_id %s NOT NULL UNIQUE,
			name %s NOT NULL,
			description %s NOT NULL DEFAULT '',
			method %s NOT NULL DEFAULT 'GET',
			api_url %s NOT NULL DEFAULT '',
			url_template %s NOT NULL DEFAULT '',
			thumbnail_url %s NOT NULL DEFAULT '',
			proxy_mode %s NOT NULL DEFAULT 'client_direct',
			timeout_ms INTEGER NOT NULL DEFAULT 8000,
			retry_count INTEGER NOT NULL DEFAULT 1,
			cache_seconds INTEGER NOT NULL DEFAULT 300,
			check_interval_sec INTEGER NOT NULL DEFAULT 300,
			enabled INTEGER NOT NULL DEFAULT 1,
			client_visible INTEGER NOT NULL DEFAULT 1,
			supported_formats %s NOT NULL,
			last_status %s NOT NULL DEFAULT 'unknown',
			last_latency_ms INTEGER NOT NULL DEFAULT 0,
			last_checked_at %s NOT NULL DEFAULT '',
			last_error %s NOT NULL,
			consecutive_failure INTEGER NOT NULL DEFAULT 0,
			created_at %s NOT NULL,
			updated_at %s NOT NULL
		)`, d.idType(), keyText, shortText, keyText, shortText, mediumText, keyText, mediumText, mediumText, mediumText, keyText, longText, keyText, shortText, longText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS endpoint_health_checks (
			id %s,
			source_db_id BIGINT NOT NULL,
			status %s NOT NULL,
			latency_ms INTEGER NOT NULL DEFAULT 0,
			error %s NOT NULL,
			checked_at %s NOT NULL
		)`, d.idType(), keyText, longText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS endpoint_call_logs (
			id %s,
			source_id %s NOT NULL,
			status %s NOT NULL,
			latency_ms INTEGER NOT NULL DEFAULT 0,
			error %s NOT NULL,
			client %s NOT NULL DEFAULT '',
			created_at %s NOT NULL
		)`, d.idType(), keyText, keyText, longText, mediumText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS database_sync_jobs (
			id %s,
			direction %s NOT NULL,
			status %s NOT NULL,
			message %s NOT NULL,
			tables_json %s NOT NULL,
			started_at %s NOT NULL,
			finished_at %s NOT NULL DEFAULT ''
		)`, d.idType(), keyText, keyText, longText, longText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS system_settings (
			%s %s NOT NULL PRIMARY KEY,
			value %s NOT NULL,
			updated_at %s NOT NULL
		)`, d.quoteIdent("key"), keyText, longText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS legacy_sync_jobs (
			id %s,
			status %s NOT NULL,
			summary %s NOT NULL,
			stats_json %s NOT NULL,
			started_at %s NOT NULL,
			finished_at %s NOT NULL DEFAULT ''
		)`, d.idType(), keyText, longText, longText, shortText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS audit_logs (
			id %s,
			actor %s NOT NULL DEFAULT '',
			type %s NOT NULL,
			target %s NOT NULL DEFAULT '',
			message %s NOT NULL,
			ip %s NOT NULL DEFAULT '',
			user_agent %s NOT NULL DEFAULT '',
			created_at %s NOT NULL
		)`, d.idType(), keyText, keyText, keyText, longText, keyText, mediumText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS legacy_json_revisions (
			id %s,
			name %s NOT NULL,
			raw %s NOT NULL,
			note %s NOT NULL DEFAULT '',
			created_by %s NOT NULL DEFAULT '',
			created_at %s NOT NULL
		)`, d.idType(), keyText, longText, mediumText, keyText, shortText),
		fmt.Sprintf(`CREATE TABLE IF NOT EXISTS webhook_deliveries (
			id %s,
			webhook_name %s NOT NULL DEFAULT '',
			event %s NOT NULL DEFAULT '',
			status %s NOT NULL DEFAULT '',
			attempts INTEGER NOT NULL DEFAULT 0,
			response_code INTEGER NOT NULL DEFAULT 0,
			error_message %s NOT NULL,
			payload_sha256 %s NOT NULL DEFAULT '',
			created_at %s NOT NULL,
			finished_at %s NOT NULL DEFAULT ''
		)`, d.idType(), keyText, keyText, keyText, longText, shortText, shortText, shortText),
		`CREATE INDEX IF NOT EXISTS idx_feedback_tickets_activity ON feedback_tickets(last_activity_at)`,
		`CREATE INDEX IF NOT EXISTS idx_feedback_comments_code ON feedback_comments(feedback_code)`,
		`CREATE INDEX IF NOT EXISTS idx_feedback_attachments_code ON feedback_attachments(feedback_code)`,
		`CREATE INDEX IF NOT EXISTS idx_feedback_events_code ON feedback_events(feedback_code)`,
		`CREATE INDEX IF NOT EXISTS idx_mail_records_code ON mail_records(feedback_code)`,
		`CREATE INDEX IF NOT EXISTS idx_endpoint_call_logs_source ON endpoint_call_logs(source_id)`,
		`CREATE INDEX IF NOT EXISTS idx_audit_logs_created ON audit_logs(created_at)`,
		`CREATE INDEX IF NOT EXISTS idx_audit_logs_type ON audit_logs(type)`,
		`CREATE INDEX IF NOT EXISTS idx_audit_logs_target ON audit_logs(target)`,
		`CREATE INDEX IF NOT EXISTS idx_legacy_json_revisions_name ON legacy_json_revisions(name, id)`,
		`CREATE INDEX IF NOT EXISTS idx_release_notices_version ON release_notices(version)`,
		`CREATE INDEX IF NOT EXISTS idx_release_notice_revisions_version ON release_notice_revisions(version, id)`,
	}
}

func (s *Store) recordSchemaVersion(conn *sql.DB, d dialect) error {
	columns := []string{"version", "applied_at", "description"}
	_, err := conn.Exec(d.rebind(d.upsert("schema_migrations", columns, []string{"version"})),
		CurrentSchemaVersion,
		Now(),
		"unified-management layered monolith baseline",
	)
	return err
}
