// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.30.0
// source: queries.sql

package database

import (
	"context"

	"github.com/jackc/pgx/v5/pgtype"
)

const AddBookToCollection = `-- name: AddBookToCollection :one

INSERT INTO collection_items (collection_id, media_item_id, added_by_user_id)
VALUES ($1, $2, $3)
ON CONFLICT (collection_id, media_item_id) DO NOTHING
RETURNING id, collection_id, media_item_id, added_at, added_by_user_id, excluded
`

type AddBookToCollectionParams struct {
	CollectionID  pgtype.UUID `db:"collection_id" json:"collection_id"`
	MediaItemID   pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	AddedByUserID pgtype.UUID `db:"added_by_user_id" json:"added_by_user_id"`
}

// COLLECTION ITEMS QUERIES
// Add book to collection
func (q *Queries) AddBookToCollection(ctx context.Context, arg AddBookToCollectionParams) (CollectionItems, error) {
	row := q.db.QueryRow(ctx, AddBookToCollection, arg.CollectionID, arg.MediaItemID, arg.AddedByUserID)
	var i CollectionItems
	err := row.Scan(
		&i.ID,
		&i.CollectionID,
		&i.MediaItemID,
		&i.AddedAt,
		&i.AddedByUserID,
		&i.Excluded,
	)
	return i, err
}

const AddBookToKoboShelf = `-- name: AddBookToKoboShelf :one

INSERT INTO kobo_shelves (device_id, media_item_id, shelf_name, shelf_position)
VALUES ($1, $2, $3, $4)
ON CONFLICT (device_id, media_item_id)
DO UPDATE SET
    shelf_name = EXCLUDED.shelf_name,
    shelf_position = EXCLUDED.shelf_position,
    last_synced_at = NOW()
RETURNING id, device_id, media_item_id, shelf_name, shelf_position, added_at, last_synced_at, collection_id, position_in_collection
`

type AddBookToKoboShelfParams struct {
	DeviceID      pgtype.UUID `db:"device_id" json:"device_id"`
	MediaItemID   pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	ShelfName     pgtype.Text `db:"shelf_name" json:"shelf_name"`
	ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"`
}

// ============================================
// KOBO SHELF MANAGEMENT QUERIES
// ============================================
func (q *Queries) AddBookToKoboShelf(ctx context.Context, arg AddBookToKoboShelfParams) (KoboShelves, error) {
	row := q.db.QueryRow(ctx, AddBookToKoboShelf,
		arg.DeviceID,
		arg.MediaItemID,
		arg.ShelfName,
		arg.ShelfPosition,
	)
	var i KoboShelves
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.ShelfName,
		&i.ShelfPosition,
		&i.AddedAt,
		&i.LastSyncedAt,
		&i.CollectionID,
		&i.PositionInCollection,
	)
	return i, err
}

const AddLibraryFolder = `-- name: AddLibraryFolder :one
INSERT INTO library_folders (library_id, folder_path) VALUES ($1, $2) RETURNING id, library_id, folder_path, created_at
`

type AddLibraryFolderParams struct {
	LibraryID  pgtype.UUID `db:"library_id" json:"library_id"`
	FolderPath string      `db:"folder_path" json:"folder_path"`
}

// Library Folders queries
func (q *Queries) AddLibraryFolder(ctx context.Context, arg AddLibraryFolderParams) (LibraryFolders, error) {
	row := q.db.QueryRow(ctx, AddLibraryFolder, arg.LibraryID, arg.FolderPath)
	var i LibraryFolders
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.FolderPath,
		&i.CreatedAt,
	)
	return i, err
}

const BulkUpdateFormatGroups = `-- name: BulkUpdateFormatGroups :exec
UPDATE media_items m
SET
    format_group = detect_format_group(m.mime_type, m.file_path),
    format_mimetype = m.mime_type,
    is_reflowable = (detect_format_group(m.mime_type, m.file_path) = 'reflowable'),
    has_fixed_layout = (detect_format_group(m.mime_type, m.file_path) IN ('fixed_layout', 'comic_archive')),
    updated_at = NOW()
WHERE m.format_group IS NULL OR m.format_group = 'unknown'
`

// Bulk update format group for all media items
func (q *Queries) BulkUpdateFormatGroups(ctx context.Context) error {
	_, err := q.db.Exec(ctx, BulkUpdateFormatGroups)
	return err
}

const BulkUpdateProgressFromSync = `-- name: BulkUpdateProgressFromSync :many
SELECT bulk_update_progress_from_koreader FROM bulk_update_progress_from_koreader($1::uuid, $2::jsonb)
`

type BulkUpdateProgressFromSyncParams struct {
	Column1 pgtype.UUID `db:"column_1" json:"column_1"`
	Column2 []byte      `db:"column_2" json:"column_2"`
}

func (q *Queries) BulkUpdateProgressFromSync(ctx context.Context, arg BulkUpdateProgressFromSyncParams) ([]interface{}, error) {
	rows, err := q.db.Query(ctx, BulkUpdateProgressFromSync, arg.Column1, arg.Column2)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []interface{}{}
	for rows.Next() {
		var bulk_update_progress_from_koreader interface{}
		if err := rows.Scan(&bulk_update_progress_from_koreader); err != nil {
			return nil, err
		}
		items = append(items, bulk_update_progress_from_koreader)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const CleanupExpiredOpdsTokens = `-- name: CleanupExpiredOpdsTokens :exec
DELETE FROM opds_tokens WHERE expires_at < NOW()
`

// Cleanup expired OPDS tokens
func (q *Queries) CleanupExpiredOpdsTokens(ctx context.Context) error {
	_, err := q.db.Exec(ctx, CleanupExpiredOpdsTokens)
	return err
}

const CleanupExpiredRefreshTokens = `-- name: CleanupExpiredRefreshTokens :exec
DELETE FROM refresh_tokens WHERE expires_at < NOW() OR (revoked_at IS NOT NULL AND revoked_at < NOW() - INTERVAL '7 days')
`

func (q *Queries) CleanupExpiredRefreshTokens(ctx context.Context) error {
	_, err := q.db.Exec(ctx, CleanupExpiredRefreshTokens)
	return err
}

const ClearDeviceSyncQueue = `-- name: ClearDeviceSyncQueue :exec
DELETE FROM sync_queue WHERE device_id = $1
`

func (q *Queries) ClearDeviceSyncQueue(ctx context.Context, deviceID pgtype.UUID) error {
	_, err := q.db.Exec(ctx, ClearDeviceSyncQueue, deviceID)
	return err
}

const ClearKoboShelf = `-- name: ClearKoboShelf :exec
DELETE FROM kobo_shelves WHERE device_id = $1
`

func (q *Queries) ClearKoboShelf(ctx context.Context, deviceID pgtype.UUID) error {
	_, err := q.db.Exec(ctx, ClearKoboShelf, deviceID)
	return err
}

const ClearKoboShelfByName = `-- name: ClearKoboShelfByName :exec
DELETE FROM kobo_shelves WHERE device_id = $1 AND shelf_name = $2
`

type ClearKoboShelfByNameParams struct {
	DeviceID  pgtype.UUID `db:"device_id" json:"device_id"`
	ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"`
}

func (q *Queries) ClearKoboShelfByName(ctx context.Context, arg ClearKoboShelfByNameParams) error {
	_, err := q.db.Exec(ctx, ClearKoboShelfByName, arg.DeviceID, arg.ShelfName)
	return err
}

const CountUnlinkedBooks = `-- name: CountUnlinkedBooks :one
SELECT COUNT(*) as count
FROM unlinked_books
WHERE device_id = $1 AND resolved = false
`

// Count unlinked books for a device
func (q *Queries) CountUnlinkedBooks(ctx context.Context, deviceID pgtype.UUID) (int64, error) {
	row := q.db.QueryRow(ctx, CountUnlinkedBooks, deviceID)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const CountUserDevices = `-- name: CountUserDevices :one
SELECT COUNT(*) FROM devices WHERE user_id = $1
`

func (q *Queries) CountUserDevices(ctx context.Context, userID pgtype.UUID) (int64, error) {
	row := q.db.QueryRow(ctx, CountUserDevices, userID)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const CreateCollection = `-- name: CreateCollection :one

INSERT INTO collections (user_id, name, description, color, icon, auto_assign_rules, view_settings)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at
`

type CreateCollectionParams struct {
	UserID          pgtype.UUID `db:"user_id" json:"user_id"`
	Name            string      `db:"name" json:"name"`
	Description     pgtype.Text `db:"description" json:"description"`
	Color           pgtype.Text `db:"color" json:"color"`
	Icon            pgtype.Text `db:"icon" json:"icon"`
	AutoAssignRules []byte      `db:"auto_assign_rules" json:"auto_assign_rules"`
	ViewSettings    []byte      `db:"view_settings" json:"view_settings"`
}

// COLLECTIONS QUERIES
// Create collection
func (q *Queries) CreateCollection(ctx context.Context, arg CreateCollectionParams) (Collections, error) {
	row := q.db.QueryRow(ctx, CreateCollection,
		arg.UserID,
		arg.Name,
		arg.Description,
		arg.Color,
		arg.Icon,
		arg.AutoAssignRules,
		arg.ViewSettings,
	)
	var i Collections
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.Name,
		&i.Description,
		&i.Color,
		&i.Icon,
		&i.AutoAssignRules,
		&i.ViewSettings,
		&i.ShowOnDashboard,
		&i.QueryType,
		&i.Priority,
		&i.IsSystemCollection,
		&i.CreatedAt,
	)
	return i, err
}

const CreateDevice = `-- name: CreateDevice :one

INSERT INTO devices (user_id, device_name, device_type, device_identifier, auth_token, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`

type CreateDeviceParams struct {
	UserID               pgtype.UUID `db:"user_id" json:"user_id"`
	DeviceName           string      `db:"device_name" json:"device_name"`
	DeviceType           string      `db:"device_type" json:"device_type"`
	DeviceIdentifier     string      `db:"device_identifier" json:"device_identifier"`
	AuthToken            string      `db:"auth_token" json:"auth_token"`
	SyncEnabled          pgtype.Bool `db:"sync_enabled" json:"sync_enabled"`
	AutoSync             pgtype.Bool `db:"auto_sync" json:"auto_sync"`
	SyncFrequencyMinutes pgtype.Int4 `db:"sync_frequency_minutes" json:"sync_frequency_minutes"`
	DeviceMetadata       []byte      `db:"device_metadata" json:"device_metadata"`
}

// ============================================
// DEVICE MANAGEMENT & AUTH
// ============================================
// Device Registration & Management
func (q *Queries) CreateDevice(ctx context.Context, arg CreateDeviceParams) (Devices, error) {
	row := q.db.QueryRow(ctx, CreateDevice,
		arg.UserID,
		arg.DeviceName,
		arg.DeviceType,
		arg.DeviceIdentifier,
		arg.AuthToken,
		arg.SyncEnabled,
		arg.AutoSync,
		arg.SyncFrequencyMinutes,
		arg.DeviceMetadata,
	)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const CreateDeviceCatalog = `-- name: CreateDeviceCatalog :one

INSERT INTO device_catalogs (device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
ON CONFLICT (device_id, kobo_content_id)
DO UPDATE SET
    available = EXCLUDED.available,
    delivery_date = COALESCE(EXCLUDED.delivery_date, device_catalogs.delivery_date),
    delivery_method = EXCLUDED.delivery_method
RETURNING id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method
`

type CreateDeviceCatalogParams struct {
	DeviceID       pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID    pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	BookhoardUuid  pgtype.UUID        `db:"bookhoard_uuid" json:"bookhoard_uuid"`
	KoboContentID  string             `db:"kobo_content_id" json:"kobo_content_id"`
	ContentIDType  pgtype.Text        `db:"content_id_type" json:"content_id_type"`
	Available      pgtype.Bool        `db:"available" json:"available"`
	DeliveryDate   pgtype.Timestamptz `db:"delivery_date" json:"delivery_date"`
	DeliveryMethod pgtype.Text        `db:"delivery_method" json:"delivery_method"`
}

// DEVICE CATALOGS QUERIES
// Create device catalog entry
func (q *Queries) CreateDeviceCatalog(ctx context.Context, arg CreateDeviceCatalogParams) (DeviceCatalogs, error) {
	row := q.db.QueryRow(ctx, CreateDeviceCatalog,
		arg.DeviceID,
		arg.MediaItemID,
		arg.BookhoardUuid,
		arg.KoboContentID,
		arg.ContentIDType,
		arg.Available,
		arg.DeliveryDate,
		arg.DeliveryMethod,
	)
	var i DeviceCatalogs
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.BookhoardUuid,
		&i.KoboContentID,
		&i.ContentIDType,
		&i.Available,
		&i.DeliveryDate,
		&i.DeliveryMethod,
	)
	return i, err
}

const CreateDeviceFileAlias = `-- name: CreateDeviceFileAlias :one

INSERT INTO device_file_aliases (media_item_id, device_id, file_path, file_sha256, confidence_score)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at
`

type CreateDeviceFileAliasParams struct {
	MediaItemID     pgtype.UUID   `db:"media_item_id" json:"media_item_id"`
	DeviceID        pgtype.UUID   `db:"device_id" json:"device_id"`
	FilePath        string        `db:"file_path" json:"file_path"`
	FileSha256      pgtype.Text   `db:"file_sha256" json:"file_sha256"`
	ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
}

// DEVICE FILE ALIASES QUERIES
// Create device file alias
func (q *Queries) CreateDeviceFileAlias(ctx context.Context, arg CreateDeviceFileAliasParams) (DeviceFileAliases, error) {
	row := q.db.QueryRow(ctx, CreateDeviceFileAlias,
		arg.MediaItemID,
		arg.DeviceID,
		arg.FilePath,
		arg.FileSha256,
		arg.ConfidenceScore,
	)
	var i DeviceFileAliases
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.DeviceID,
		&i.FilePath,
		&i.FileSha256,
		&i.ConfidenceScore,
		&i.LastSeenAt,
	)
	return i, err
}

const CreateDeviceShelfMapping = `-- name: CreateDeviceShelfMapping :one

INSERT INTO device_shelf_mappings (collection_id, device_id, device_shelf_name, sync_direction)
VALUES ($1, $2, $3, $4)
ON CONFLICT (collection_id, device_id)
DO UPDATE SET
    device_shelf_name = EXCLUDED.device_shelf_name,
    sync_direction = EXCLUDED.sync_direction
RETURNING id, collection_id, device_id, device_shelf_name, sync_direction, created_at
`

type CreateDeviceShelfMappingParams struct {
	CollectionID    pgtype.UUID `db:"collection_id" json:"collection_id"`
	DeviceID        pgtype.UUID `db:"device_id" json:"device_id"`
	DeviceShelfName pgtype.Text `db:"device_shelf_name" json:"device_shelf_name"`
	SyncDirection   pgtype.Text `db:"sync_direction" json:"sync_direction"`
}

// DEVICE SHELF MAPPINGS QUERIES
// Create device shelf mapping
func (q *Queries) CreateDeviceShelfMapping(ctx context.Context, arg CreateDeviceShelfMappingParams) (DeviceShelfMappings, error) {
	row := q.db.QueryRow(ctx, CreateDeviceShelfMapping,
		arg.CollectionID,
		arg.DeviceID,
		arg.DeviceShelfName,
		arg.SyncDirection,
	)
	var i DeviceShelfMappings
	err := row.Scan(
		&i.ID,
		&i.CollectionID,
		&i.DeviceID,
		&i.DeviceShelfName,
		&i.SyncDirection,
		&i.CreatedAt,
	)
	return i, err
}

const CreateLibrary = `-- name: CreateLibrary :one
INSERT INTO libraries (name, description, library_type_id, created_by_admin_id)
VALUES ($1, $2, $3, $4)
RETURNING id, name, description, library_type_id, created_by_admin_id, created_at, updated_at
`

type CreateLibraryParams struct {
	Name             string      `db:"name" json:"name"`
	Description      pgtype.Text `db:"description" json:"description"`
	LibraryTypeID    pgtype.UUID `db:"library_type_id" json:"library_type_id"`
	CreatedByAdminID pgtype.UUID `db:"created_by_admin_id" json:"created_by_admin_id"`
}

// Libraries queries
func (q *Queries) CreateLibrary(ctx context.Context, arg CreateLibraryParams) (Libraries, error) {
	row := q.db.QueryRow(ctx, CreateLibrary,
		arg.Name,
		arg.Description,
		arg.LibraryTypeID,
		arg.CreatedByAdminID,
	)
	var i Libraries
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.Description,
		&i.LibraryTypeID,
		&i.CreatedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const CreateMediaHighlight = `-- name: CreateMediaHighlight :one
INSERT INTO media_highlights (media_item_id, user_id, selection_text, start_position, end_position, color, note_id)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data
`

type CreateMediaHighlightParams struct {
	MediaItemID   pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID        pgtype.UUID `db:"user_id" json:"user_id"`
	SelectionText string      `db:"selection_text" json:"selection_text"`
	StartPosition pgtype.Text `db:"start_position" json:"start_position"`
	EndPosition   pgtype.Text `db:"end_position" json:"end_position"`
	Color         pgtype.Text `db:"color" json:"color"`
	NoteID        pgtype.UUID `db:"note_id" json:"note_id"`
}

// Media Highlights queries
func (q *Queries) CreateMediaHighlight(ctx context.Context, arg CreateMediaHighlightParams) (MediaHighlights, error) {
	row := q.db.QueryRow(ctx, CreateMediaHighlight,
		arg.MediaItemID,
		arg.UserID,
		arg.SelectionText,
		arg.StartPosition,
		arg.EndPosition,
		arg.Color,
		arg.NoteID,
	)
	var i MediaHighlights
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.SelectionText,
		&i.StartPosition,
		&i.EndPosition,
		&i.Color,
		&i.NoteID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PercentageStart,
		&i.PercentageEnd,
		&i.CharacterStart,
		&i.CharacterEnd,
		&i.EpubcfiStart,
		&i.EpubcfiEnd,
		&i.ChapterReference,
		&i.ParagraphStart,
		&i.ParagraphEnd,
		&i.PanelNumber,
		&i.DeviceSyncData,
	)
	return i, err
}

const CreateMediaItem = `-- name: CreateMediaItem :one
INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, tags_search, asin, date_published, publisher, contributors, contributors_search, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28)
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`

type CreateMediaItemParams struct {
	LibraryID          pgtype.UUID        `db:"library_id" json:"library_id"`
	Title              string             `db:"title" json:"title"`
	Author             pgtype.Text        `db:"author" json:"author"`
	Isbn               pgtype.Text        `db:"isbn" json:"isbn"`
	Description        pgtype.Text        `db:"description" json:"description"`
	FilePath           string             `db:"file_path" json:"file_path"`
	FileSize           pgtype.Int8        `db:"file_size" json:"file_size"`
	MimeType           pgtype.Text        `db:"mime_type" json:"mime_type"`
	CoverImagePath     pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text        `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4        `db:"series_number" json:"series_number"`
	Tags               []string           `db:"tags" json:"tags"`
	TagsSearch         []string           `db:"tags_search" json:"tags_search"`
	Asin               pgtype.Text        `db:"asin" json:"asin"`
	DatePublished      pgtype.Date        `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text        `db:"publisher" json:"publisher"`
	Contributors       []string           `db:"contributors" json:"contributors"`
	ContributorsSearch []string           `db:"contributors_search" json:"contributors_search"`
	Language           pgtype.Text        `db:"language" json:"language"`
	Edition            pgtype.Text        `db:"edition" json:"edition"`
	PageCount          pgtype.Int4        `db:"page_count" json:"page_count"`
	Genre              pgtype.Text        `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4        `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text        `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text        `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text        `db:"google_books_id" json:"google_books_id"`
	AddedByAdminID     pgtype.UUID        `db:"added_by_admin_id" json:"added_by_admin_id"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
}

// Media Items queries
func (q *Queries) CreateMediaItem(ctx context.Context, arg CreateMediaItemParams) (MediaItems, error) {
	row := q.db.QueryRow(ctx, CreateMediaItem,
		arg.LibraryID,
		arg.Title,
		arg.Author,
		arg.Isbn,
		arg.Description,
		arg.FilePath,
		arg.FileSize,
		arg.MimeType,
		arg.CoverImagePath,
		arg.Series,
		arg.SeriesNumber,
		arg.Tags,
		arg.TagsSearch,
		arg.Asin,
		arg.DatePublished,
		arg.Publisher,
		arg.Contributors,
		arg.ContributorsSearch,
		arg.Language,
		arg.Edition,
		arg.PageCount,
		arg.Genre,
		arg.CopyrightYear,
		arg.GoodreadsID,
		arg.OpenlibraryID,
		arg.GoogleBooksID,
		arg.AddedByAdminID,
		arg.CreatedAt,
	)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const CreateMediaItemFormat = `-- name: CreateMediaItemFormat :one

INSERT INTO media_item_formats (media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, converted_from_format_id)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id
`

type CreateMediaItemFormatParams struct {
	MediaItemID           pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	FormatType            string      `db:"format_type" json:"format_type"`
	FilePath              pgtype.Text `db:"file_path" json:"file_path"`
	FileSha256            pgtype.Text `db:"file_sha256" json:"file_sha256"`
	FileSizeBytes         pgtype.Int8 `db:"file_size_bytes" json:"file_size_bytes"`
	MimeType              pgtype.Text `db:"mime_type" json:"mime_type"`
	ConvertedFromFormatID pgtype.UUID `db:"converted_from_format_id" json:"converted_from_format_id"`
}

// MEDIA ITEM FORMATS QUERIES
// Create media item format
func (q *Queries) CreateMediaItemFormat(ctx context.Context, arg CreateMediaItemFormatParams) (MediaItemFormats, error) {
	row := q.db.QueryRow(ctx, CreateMediaItemFormat,
		arg.MediaItemID,
		arg.FormatType,
		arg.FilePath,
		arg.FileSha256,
		arg.FileSizeBytes,
		arg.MimeType,
		arg.ConvertedFromFormatID,
	)
	var i MediaItemFormats
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.FormatType,
		&i.FilePath,
		&i.FileSha256,
		&i.FileSizeBytes,
		&i.MimeType,
		&i.CreatedAt,
		&i.ConvertedFromFormatID,
	)
	return i, err
}

const CreateMediaNote = `-- name: CreateMediaNote :one
INSERT INTO media_notes (media_item_id, user_id, content, position)
VALUES ($1, $2, $3, $4)
RETURNING id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data
`

type CreateMediaNoteParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
	Content     string      `db:"content" json:"content"`
	Position    pgtype.Text `db:"position" json:"position"`
}

// Media Notes queries
func (q *Queries) CreateMediaNote(ctx context.Context, arg CreateMediaNoteParams) (MediaNotes, error) {
	row := q.db.QueryRow(ctx, CreateMediaNote,
		arg.MediaItemID,
		arg.UserID,
		arg.Content,
		arg.Position,
	)
	var i MediaNotes
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.Content,
		&i.Position,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PercentageLocation,
		&i.CharacterStart,
		&i.CharacterEnd,
		&i.EpubcfiLocation,
		&i.ChapterReference,
		&i.ParagraphReference,
		&i.DeviceSyncData,
	)
	return i, err
}

const CreateMediaRating = `-- name: CreateMediaRating :one
INSERT INTO media_ratings (media_item_id, user_id, rating)
VALUES ($1, $2, $3)
ON CONFLICT (media_item_id, user_id)
DO UPDATE SET
    rating = EXCLUDED.rating,
    updated_at = NOW()
RETURNING id, media_item_id, user_id, rating, created_at, updated_at
`

type CreateMediaRatingParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
	Rating      int32       `db:"rating" json:"rating"`
}

func (q *Queries) CreateMediaRating(ctx context.Context, arg CreateMediaRatingParams) (MediaRatings, error) {
	row := q.db.QueryRow(ctx, CreateMediaRating, arg.MediaItemID, arg.UserID, arg.Rating)
	var i MediaRatings
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.Rating,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const CreateOpdsToken = `-- name: CreateOpdsToken :one

INSERT INTO opds_tokens (device_id, token, token_type, expires_at)
VALUES ($1, $2, $3, $4)
RETURNING id, device_id, token, token_type, expires_at, created_at
`

type CreateOpdsTokenParams struct {
	DeviceID  pgtype.UUID        `db:"device_id" json:"device_id"`
	Token     string             `db:"token" json:"token"`
	TokenType pgtype.Text        `db:"token_type" json:"token_type"`
	ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"`
}

// OPDS TOKENS QUERIES
// Create OPDS token
func (q *Queries) CreateOpdsToken(ctx context.Context, arg CreateOpdsTokenParams) (OpdsTokens, error) {
	row := q.db.QueryRow(ctx, CreateOpdsToken,
		arg.DeviceID,
		arg.Token,
		arg.TokenType,
		arg.ExpiresAt,
	)
	var i OpdsTokens
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.Token,
		&i.TokenType,
		&i.ExpiresAt,
		&i.CreatedAt,
	)
	return i, err
}

const CreateOrUpdateKoboEntitlement = `-- name: CreateOrUpdateKoboEntitlement :one

INSERT INTO kobo_entitlements (device_id, media_item_id, entitlement_id, content_id, revision_number, purchase_date, kobo_metadata)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (device_id, entitlement_id)
DO UPDATE SET
    content_id = EXCLUDED.content_id,
    revision_number = EXCLUDED.revision_number,
    purchase_date = COALESCE(EXCLUDED.purchase_date, kobo_entitlements.purchase_date),
    book_status = 'installed',
    sync_status = 'synced',
    kobo_metadata = EXCLUDED.kobo_metadata,
    updated_at = NOW()
RETURNING id, device_id, media_item_id, entitlement_id, content_id, revision_number, purchase_date, accession_date, book_status, sync_status, kobo_metadata, created_at, updated_at
`

type CreateOrUpdateKoboEntitlementParams struct {
	DeviceID       pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID    pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	EntitlementID  string             `db:"entitlement_id" json:"entitlement_id"`
	ContentID      string             `db:"content_id" json:"content_id"`
	RevisionNumber pgtype.Int4        `db:"revision_number" json:"revision_number"`
	PurchaseDate   pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"`
	KoboMetadata   []byte             `db:"kobo_metadata" json:"kobo_metadata"`
}

// ============================================
// KOBO ENTITLEMENT QUERIES
// ============================================
func (q *Queries) CreateOrUpdateKoboEntitlement(ctx context.Context, arg CreateOrUpdateKoboEntitlementParams) (KoboEntitlements, error) {
	row := q.db.QueryRow(ctx, CreateOrUpdateKoboEntitlement,
		arg.DeviceID,
		arg.MediaItemID,
		arg.EntitlementID,
		arg.ContentID,
		arg.RevisionNumber,
		arg.PurchaseDate,
		arg.KoboMetadata,
	)
	var i KoboEntitlements
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.EntitlementID,
		&i.ContentID,
		&i.RevisionNumber,
		&i.PurchaseDate,
		&i.AccessionDate,
		&i.BookStatus,
		&i.SyncStatus,
		&i.KoboMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const CreateReadingHistory = `-- name: CreateReadingHistory :one
INSERT INTO reading_history (
    user_id,
    media_item_id,
    device_id,
    progress_percentage,
    reading_session_start,
    reading_session_end,
    pages_read,
    time_spent_seconds,
    device_metadata
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id, user_id, media_item_id, device_id, progress_percentage, reading_session_start, reading_session_end, pages_read, time_spent_seconds, device_metadata, created_at
`

type CreateReadingHistoryParams struct {
	UserID              pgtype.UUID        `db:"user_id" json:"user_id"`
	MediaItemID         pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	DeviceID            pgtype.UUID        `db:"device_id" json:"device_id"`
	ProgressPercentage  pgtype.Float8      `db:"progress_percentage" json:"progress_percentage"`
	ReadingSessionStart pgtype.Timestamptz `db:"reading_session_start" json:"reading_session_start"`
	ReadingSessionEnd   pgtype.Timestamptz `db:"reading_session_end" json:"reading_session_end"`
	PagesRead           pgtype.Int4        `db:"pages_read" json:"pages_read"`
	TimeSpentSeconds    pgtype.Int4        `db:"time_spent_seconds" json:"time_spent_seconds"`
	DeviceMetadata      []byte             `db:"device_metadata" json:"device_metadata"`
}

// Create reading history entry
func (q *Queries) CreateReadingHistory(ctx context.Context, arg CreateReadingHistoryParams) (ReadingHistory, error) {
	row := q.db.QueryRow(ctx, CreateReadingHistory,
		arg.UserID,
		arg.MediaItemID,
		arg.DeviceID,
		arg.ProgressPercentage,
		arg.ReadingSessionStart,
		arg.ReadingSessionEnd,
		arg.PagesRead,
		arg.TimeSpentSeconds,
		arg.DeviceMetadata,
	)
	var i ReadingHistory
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.MediaItemID,
		&i.DeviceID,
		&i.ProgressPercentage,
		&i.ReadingSessionStart,
		&i.ReadingSessionEnd,
		&i.PagesRead,
		&i.TimeSpentSeconds,
		&i.DeviceMetadata,
		&i.CreatedAt,
	)
	return i, err
}

const CreateRefreshToken = `-- name: CreateRefreshToken :one
INSERT INTO refresh_tokens (user_id, token, expires_at)
VALUES ($1, $2, $3)
RETURNING id, user_id, token, expires_at, created_at, revoked_at
`

type CreateRefreshTokenParams struct {
	UserID    pgtype.UUID        `db:"user_id" json:"user_id"`
	Token     pgtype.UUID        `db:"token" json:"token"`
	ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"`
}

// Refresh Tokens queries
func (q *Queries) CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshTokens, error) {
	row := q.db.QueryRow(ctx, CreateRefreshToken, arg.UserID, arg.Token, arg.ExpiresAt)
	var i RefreshTokens
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.Token,
		&i.ExpiresAt,
		&i.CreatedAt,
		&i.RevokedAt,
	)
	return i, err
}

const CreateSyncConflict = `-- name: CreateSyncConflict :one
INSERT INTO sync_conflicts (media_item_id, user_id, conflict_type, conflict_data)
VALUES ($1, $2, $3, $4)
RETURNING id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at
`

type CreateSyncConflictParams struct {
	MediaItemID  pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID       pgtype.UUID `db:"user_id" json:"user_id"`
	ConflictType string      `db:"conflict_type" json:"conflict_type"`
	ConflictData []byte      `db:"conflict_data" json:"conflict_data"`
}

// Conflict Resolution
func (q *Queries) CreateSyncConflict(ctx context.Context, arg CreateSyncConflictParams) (SyncConflicts, error) {
	row := q.db.QueryRow(ctx, CreateSyncConflict,
		arg.MediaItemID,
		arg.UserID,
		arg.ConflictType,
		arg.ConflictData,
	)
	var i SyncConflicts
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.ConflictType,
		&i.ConflictData,
		&i.ResolutionStatus,
		&i.ResolutionData,
		&i.ResolvedBy,
		&i.ResolvedAt,
		&i.CreatedAt,
	)
	return i, err
}

const CreateSyncHistoryEntry = `-- name: CreateSyncHistoryEntry :one
INSERT INTO sync_queue (device_id, media_item_id, sync_type, sync_data, priority, status)
VALUES ($1, $2, 'koreader_progress', $3, 5, 'completed')
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`

type CreateSyncHistoryEntryParams struct {
	DeviceID    pgtype.UUID `db:"device_id" json:"device_id"`
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	SyncData    []byte      `db:"sync_data" json:"sync_data"`
}

func (q *Queries) CreateSyncHistoryEntry(ctx context.Context, arg CreateSyncHistoryEntryParams) (SyncQueue, error) {
	row := q.db.QueryRow(ctx, CreateSyncHistoryEntry, arg.DeviceID, arg.MediaItemID, arg.SyncData)
	var i SyncQueue
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.SyncType,
		&i.SyncData,
		&i.Priority,
		&i.Attempts,
		&i.MaxAttempts,
		&i.Status,
		&i.ErrorMessage,
		&i.CreatedAt,
		&i.ProcessedAt,
	)
	return i, err
}

const CreateSyncQueueItem = `-- name: CreateSyncQueueItem :one
INSERT INTO sync_queue (device_id, media_item_id, sync_type, sync_data, priority, max_attempts, status)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`

type CreateSyncQueueItemParams struct {
	DeviceID    pgtype.UUID `db:"device_id" json:"device_id"`
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	SyncType    string      `db:"sync_type" json:"sync_type"`
	SyncData    []byte      `db:"sync_data" json:"sync_data"`
	Priority    pgtype.Int4 `db:"priority" json:"priority"`
	MaxAttempts pgtype.Int4 `db:"max_attempts" json:"max_attempts"`
	Status      pgtype.Text `db:"status" json:"status"`
}

// Sync Queue Management
func (q *Queries) CreateSyncQueueItem(ctx context.Context, arg CreateSyncQueueItemParams) (SyncQueue, error) {
	row := q.db.QueryRow(ctx, CreateSyncQueueItem,
		arg.DeviceID,
		arg.MediaItemID,
		arg.SyncType,
		arg.SyncData,
		arg.Priority,
		arg.MaxAttempts,
		arg.Status,
	)
	var i SyncQueue
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.SyncType,
		&i.SyncData,
		&i.Priority,
		&i.Attempts,
		&i.MaxAttempts,
		&i.Status,
		&i.ErrorMessage,
		&i.CreatedAt,
		&i.ProcessedAt,
	)
	return i, err
}

const CreateSystemCollection = `-- name: CreateSystemCollection :one
INSERT INTO collections (user_id, name, description, icon, color, show_on_dashboard, query_type, priority, is_system_collection, auto_assign_rules)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, true, 'null'::jsonb)
RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at
`

type CreateSystemCollectionParams struct {
	UserID          pgtype.UUID `db:"user_id" json:"user_id"`
	Name            string      `db:"name" json:"name"`
	Description     pgtype.Text `db:"description" json:"description"`
	Icon            pgtype.Text `db:"icon" json:"icon"`
	Color           pgtype.Text `db:"color" json:"color"`
	ShowOnDashboard pgtype.Bool `db:"show_on_dashboard" json:"show_on_dashboard"`
	QueryType       pgtype.Text `db:"query_type" json:"query_type"`
	Priority        pgtype.Int4 `db:"priority" json:"priority"`
}

func (q *Queries) CreateSystemCollection(ctx context.Context, arg CreateSystemCollectionParams) (Collections, error) {
	row := q.db.QueryRow(ctx, CreateSystemCollection,
		arg.UserID,
		arg.Name,
		arg.Description,
		arg.Icon,
		arg.Color,
		arg.ShowOnDashboard,
		arg.QueryType,
		arg.Priority,
	)
	var i Collections
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.Name,
		&i.Description,
		&i.Color,
		&i.Icon,
		&i.AutoAssignRules,
		&i.ViewSettings,
		&i.ShowOnDashboard,
		&i.QueryType,
		&i.Priority,
		&i.IsSystemCollection,
		&i.CreatedAt,
	)
	return i, err
}

const CreateUnlinkedBook = `-- name: CreateUnlinkedBook :one

INSERT INTO unlinked_books (device_id, content_id, file_path, title, author, confidence_score)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at
`

type CreateUnlinkedBookParams struct {
	DeviceID        pgtype.UUID   `db:"device_id" json:"device_id"`
	ContentID       string        `db:"content_id" json:"content_id"`
	FilePath        pgtype.Text   `db:"file_path" json:"file_path"`
	Title           pgtype.Text   `db:"title" json:"title"`
	Author          pgtype.Text   `db:"author" json:"author"`
	ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
}

// ============================================
// ENHANCED KOBO SYNC
// ============================================
// Create unlinked book entry
func (q *Queries) CreateUnlinkedBook(ctx context.Context, arg CreateUnlinkedBookParams) (UnlinkedBooks, error) {
	row := q.db.QueryRow(ctx, CreateUnlinkedBook,
		arg.DeviceID,
		arg.ContentID,
		arg.FilePath,
		arg.Title,
		arg.Author,
		arg.ConfidenceScore,
	)
	var i UnlinkedBooks
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.ContentID,
		&i.FilePath,
		&i.Title,
		&i.Author,
		&i.ConfidenceScore,
		&i.Resolved,
		&i.MediaItemID,
		&i.ResolvedAt,
		&i.ResolutionMethod,
		&i.LastSeenAt,
		&i.CreatedAt,
	)
	return i, err
}

const CreateUser = `-- name: CreateUser :one
INSERT INTO users (email, username, password_hash, first_name, last_name, theme, role)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, email, username, theme, first_name, last_name, role, created_at, updated_at
`

type CreateUserParams struct {
	Email        string      `db:"email" json:"email"`
	Username     string      `db:"username" json:"username"`
	PasswordHash string      `db:"password_hash" json:"password_hash"`
	FirstName    pgtype.Text `db:"first_name" json:"first_name"`
	LastName     pgtype.Text `db:"last_name" json:"last_name"`
	Theme        pgtype.Text `db:"theme" json:"theme"`
	Role         string      `db:"role" json:"role"`
}

type CreateUserRow struct {
	ID        pgtype.UUID        `db:"id" json:"id"`
	Email     string             `db:"email" json:"email"`
	Username  string             `db:"username" json:"username"`
	Theme     pgtype.Text        `db:"theme" json:"theme"`
	FirstName pgtype.Text        `db:"first_name" json:"first_name"`
	LastName  pgtype.Text        `db:"last_name" json:"last_name"`
	Role      string             `db:"role" json:"role"`
	CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}

func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateUserRow, error) {
	row := q.db.QueryRow(ctx, CreateUser,
		arg.Email,
		arg.Username,
		arg.PasswordHash,
		arg.FirstName,
		arg.LastName,
		arg.Theme,
		arg.Role,
	)
	var i CreateUserRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.Username,
		&i.Theme,
		&i.FirstName,
		&i.LastName,
		&i.Role,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const DeleteCollection = `-- name: DeleteCollection :exec
DELETE FROM collections WHERE id = $1
`

// Delete collection
func (q *Queries) DeleteCollection(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteCollection, id)
	return err
}

const DeleteDevice = `-- name: DeleteDevice :exec
DELETE FROM devices WHERE id = $1
`

func (q *Queries) DeleteDevice(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteDevice, id)
	return err
}

const DeleteDeviceByToken = `-- name: DeleteDeviceByToken :exec
DELETE FROM devices WHERE auth_token = $1
`

func (q *Queries) DeleteDeviceByToken(ctx context.Context, authToken string) error {
	_, err := q.db.Exec(ctx, DeleteDeviceByToken, authToken)
	return err
}

const DeleteDeviceCatalog = `-- name: DeleteDeviceCatalog :exec
DELETE FROM device_catalogs WHERE id = $1
`

// Delete device catalog entry
func (q *Queries) DeleteDeviceCatalog(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteDeviceCatalog, id)
	return err
}

const DeleteDeviceFileAlias = `-- name: DeleteDeviceFileAlias :exec
DELETE FROM device_file_aliases WHERE id = $1
`

// Delete device file alias
func (q *Queries) DeleteDeviceFileAlias(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteDeviceFileAlias, id)
	return err
}

const DeleteDeviceShelfMapping = `-- name: DeleteDeviceShelfMapping :exec
DELETE FROM device_shelf_mappings WHERE id = $1
`

// Delete device shelf mapping
func (q *Queries) DeleteDeviceShelfMapping(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteDeviceShelfMapping, id)
	return err
}

const DeleteKoboEntitlement = `-- name: DeleteKoboEntitlement :exec
DELETE FROM kobo_entitlements WHERE device_id = $1 AND entitlement_id = $2
`

type DeleteKoboEntitlementParams struct {
	DeviceID      pgtype.UUID `db:"device_id" json:"device_id"`
	EntitlementID string      `db:"entitlement_id" json:"entitlement_id"`
}

func (q *Queries) DeleteKoboEntitlement(ctx context.Context, arg DeleteKoboEntitlementParams) error {
	_, err := q.db.Exec(ctx, DeleteKoboEntitlement, arg.DeviceID, arg.EntitlementID)
	return err
}

const DeleteLibrary = `-- name: DeleteLibrary :exec
DELETE FROM libraries WHERE id = $1
`

func (q *Queries) DeleteLibrary(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteLibrary, id)
	return err
}

const DeleteLibraryFolder = `-- name: DeleteLibraryFolder :one
DELETE FROM library_folders WHERE library_id = $1 AND folder_path = $2 RETURNING id, library_id, folder_path, created_at
`

type DeleteLibraryFolderParams struct {
	LibraryID  pgtype.UUID `db:"library_id" json:"library_id"`
	FolderPath string      `db:"folder_path" json:"folder_path"`
}

func (q *Queries) DeleteLibraryFolder(ctx context.Context, arg DeleteLibraryFolderParams) (LibraryFolders, error) {
	row := q.db.QueryRow(ctx, DeleteLibraryFolder, arg.LibraryID, arg.FolderPath)
	var i LibraryFolders
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.FolderPath,
		&i.CreatedAt,
	)
	return i, err
}

const DeleteMediaHighlight = `-- name: DeleteMediaHighlight :exec
DELETE FROM media_highlights WHERE id = $1
`

func (q *Queries) DeleteMediaHighlight(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteMediaHighlight, id)
	return err
}

const DeleteMediaItem = `-- name: DeleteMediaItem :exec
DELETE FROM media_items WHERE id = $1
`

func (q *Queries) DeleteMediaItem(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteMediaItem, id)
	return err
}

const DeleteMediaItemFormat = `-- name: DeleteMediaItemFormat :exec
DELETE FROM media_item_formats WHERE id = $1
`

// Delete media item format
func (q *Queries) DeleteMediaItemFormat(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteMediaItemFormat, id)
	return err
}

const DeleteMediaNote = `-- name: DeleteMediaNote :exec
DELETE FROM media_notes WHERE id = $1
`

func (q *Queries) DeleteMediaNote(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteMediaNote, id)
	return err
}

const DeleteMediaRating = `-- name: DeleteMediaRating :exec
DELETE FROM media_ratings WHERE media_item_id = $1 AND user_id = $2
`

type DeleteMediaRatingParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

func (q *Queries) DeleteMediaRating(ctx context.Context, arg DeleteMediaRatingParams) error {
	_, err := q.db.Exec(ctx, DeleteMediaRating, arg.MediaItemID, arg.UserID)
	return err
}

const DeleteReadingProgress = `-- name: DeleteReadingProgress :exec
DELETE FROM reading_progress WHERE media_item_id = $1 AND user_id = $2
`

type DeleteReadingProgressParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

func (q *Queries) DeleteReadingProgress(ctx context.Context, arg DeleteReadingProgressParams) error {
	_, err := q.db.Exec(ctx, DeleteReadingProgress, arg.MediaItemID, arg.UserID)
	return err
}

const DeleteSyncConflict = `-- name: DeleteSyncConflict :exec
DELETE FROM sync_conflicts WHERE id = $1
`

func (q *Queries) DeleteSyncConflict(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteSyncConflict, id)
	return err
}

const DeleteSyncQueueItem = `-- name: DeleteSyncQueueItem :exec
DELETE FROM sync_queue WHERE id = $1
`

func (q *Queries) DeleteSyncQueueItem(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteSyncQueueItem, id)
	return err
}

const DeleteSystemConfig = `-- name: DeleteSystemConfig :exec
DELETE FROM system_config WHERE key = $1
`

// Delete system config
func (q *Queries) DeleteSystemConfig(ctx context.Context, key string) error {
	_, err := q.db.Exec(ctx, DeleteSystemConfig, key)
	return err
}

const DeleteUnlinkedBook = `-- name: DeleteUnlinkedBook :exec
DELETE FROM unlinked_books WHERE id = $1
`

// Delete unlinked book
func (q *Queries) DeleteUnlinkedBook(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteUnlinkedBook, id)
	return err
}

const DeleteUser = `-- name: DeleteUser :exec
DELETE FROM users WHERE id = $1
`

func (q *Queries) DeleteUser(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, DeleteUser, id)
	return err
}

const DeleteUserSystemCollection = `-- name: DeleteUserSystemCollection :exec
DELETE FROM collections
WHERE user_id = $1
  AND name = $2
  AND is_system_collection = true
`

type DeleteUserSystemCollectionParams struct {
	UserID pgtype.UUID `db:"user_id" json:"user_id"`
	Name   string      `db:"name" json:"name"`
}

func (q *Queries) DeleteUserSystemCollection(ctx context.Context, arg DeleteUserSystemCollectionParams) error {
	_, err := q.db.Exec(ctx, DeleteUserSystemCollection, arg.UserID, arg.Name)
	return err
}

const GenerateKoboEntitlementId = `-- name: GenerateKoboEntitlementId :one
SELECT 'kobo_' || uuid_generate_v4()::TEXT as entitlement_id
`

func (q *Queries) GenerateKoboEntitlementId(ctx context.Context) (interface{}, error) {
	row := q.db.QueryRow(ctx, GenerateKoboEntitlementId)
	var entitlement_id interface{}
	err := row.Scan(&entitlement_id)
	return entitlement_id, err
}

const GetAllSystemConfig = `-- name: GetAllSystemConfig :many
SELECT key, value, updated_at, updated_by FROM system_config ORDER BY key
`

// Get all system config
func (q *Queries) GetAllSystemConfig(ctx context.Context) ([]SystemConfig, error) {
	rows, err := q.db.Query(ctx, GetAllSystemConfig)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []SystemConfig{}
	for rows.Next() {
		var i SystemConfig
		if err := rows.Scan(
			&i.Key,
			&i.Value,
			&i.UpdatedAt,
			&i.UpdatedBy,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetAllSystemSettings = `-- name: GetAllSystemSettings :many
SELECT setting_key, setting_value, description FROM system_settings ORDER BY setting_key
`

type GetAllSystemSettingsRow struct {
	SettingKey   string      `db:"setting_key" json:"setting_key"`
	SettingValue string      `db:"setting_value" json:"setting_value"`
	Description  pgtype.Text `db:"description" json:"description"`
}

func (q *Queries) GetAllSystemSettings(ctx context.Context) ([]GetAllSystemSettingsRow, error) {
	rows, err := q.db.Query(ctx, GetAllSystemSettings)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetAllSystemSettingsRow{}
	for rows.Next() {
		var i GetAllSystemSettingsRow
		if err := rows.Scan(&i.SettingKey, &i.SettingValue, &i.Description); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetAnnotationsForBook = `-- name: GetAnnotationsForBook :many
SELECT
    mh.id,
    mh.selection_text,
    mh.start_position,
    mh.end_position,
    mh.color,
    mh.created_at,
    mh.updated_at,
    'highlight' as annotation_type,
    mh.percentage_start,
    mh.percentage_end,
    mh.epubcfi_start,
    mh.epubcfi_end
FROM media_highlights mh
WHERE mh.media_item_id = $1 AND mh.user_id = $2
UNION ALL
SELECT
    mn.id,
    mn.content,
    mn.position,
    NULL as end_position,
    NULL as color,
    mn.created_at,
    mn.updated_at,
    'note' as annotation_type,
    mn.percentage_location as percentage_start,
    NULL as percentage_end,
    mn.epubcfi_location as epubcfi_start,
    NULL as epubcfi_end
FROM media_notes mn
WHERE mn.media_item_id = $1 AND mn.user_id = $2
ORDER BY created_at DESC
`

type GetAnnotationsForBookParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

type GetAnnotationsForBookRow struct {
	ID              pgtype.UUID        `db:"id" json:"id"`
	SelectionText   string             `db:"selection_text" json:"selection_text"`
	StartPosition   pgtype.Text        `db:"start_position" json:"start_position"`
	EndPosition     pgtype.Text        `db:"end_position" json:"end_position"`
	Color           pgtype.Text        `db:"color" json:"color"`
	CreatedAt       pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt       pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	AnnotationType  string             `db:"annotation_type" json:"annotation_type"`
	PercentageStart pgtype.Float8      `db:"percentage_start" json:"percentage_start"`
	PercentageEnd   pgtype.Float8      `db:"percentage_end" json:"percentage_end"`
	EpubcfiStart    pgtype.Text        `db:"epubcfi_start" json:"epubcfi_start"`
	EpubcfiEnd      pgtype.Text        `db:"epubcfi_end" json:"epubcfi_end"`
}

func (q *Queries) GetAnnotationsForBook(ctx context.Context, arg GetAnnotationsForBookParams) ([]GetAnnotationsForBookRow, error) {
	rows, err := q.db.Query(ctx, GetAnnotationsForBook, arg.MediaItemID, arg.UserID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetAnnotationsForBookRow{}
	for rows.Next() {
		var i GetAnnotationsForBookRow
		if err := rows.Scan(
			&i.ID,
			&i.SelectionText,
			&i.StartPosition,
			&i.EndPosition,
			&i.Color,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.AnnotationType,
			&i.PercentageStart,
			&i.PercentageEnd,
			&i.EpubcfiStart,
			&i.EpubcfiEnd,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetCollection = `-- name: GetCollection :one
SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections WHERE id = $1
`

// Get collection
func (q *Queries) GetCollection(ctx context.Context, id pgtype.UUID) (Collections, error) {
	row := q.db.QueryRow(ctx, GetCollection, id)
	var i Collections
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.Name,
		&i.Description,
		&i.Color,
		&i.Icon,
		&i.AutoAssignRules,
		&i.ViewSettings,
		&i.ShowOnDashboard,
		&i.QueryType,
		&i.Priority,
		&i.IsSystemCollection,
		&i.CreatedAt,
	)
	return i, err
}

const GetCollectionItems = `-- name: GetCollectionItems :many
SELECT ci.id, ci.collection_id, ci.media_item_id, ci.added_at, ci.added_by_user_id, ci.excluded, mi.title, mi.author, mi.cover_image_path, mi.library_id
FROM collection_items ci
JOIN media_items mi ON ci.media_item_id = mi.id
WHERE ci.collection_id = $1
ORDER BY ci.added_at DESC
`

type GetCollectionItemsRow struct {
	ID             pgtype.UUID        `db:"id" json:"id"`
	CollectionID   pgtype.UUID        `db:"collection_id" json:"collection_id"`
	MediaItemID    pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	AddedAt        pgtype.Timestamptz `db:"added_at" json:"added_at"`
	AddedByUserID  pgtype.UUID        `db:"added_by_user_id" json:"added_by_user_id"`
	Excluded       pgtype.Bool        `db:"excluded" json:"excluded"`
	Title          string             `db:"title" json:"title"`
	Author         pgtype.Text        `db:"author" json:"author"`
	CoverImagePath pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	LibraryID      pgtype.UUID        `db:"library_id" json:"library_id"`
}

// Get collection items
func (q *Queries) GetCollectionItems(ctx context.Context, collectionID pgtype.UUID) ([]GetCollectionItemsRow, error) {
	rows, err := q.db.Query(ctx, GetCollectionItems, collectionID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetCollectionItemsRow{}
	for rows.Next() {
		var i GetCollectionItemsRow
		if err := rows.Scan(
			&i.ID,
			&i.CollectionID,
			&i.MediaItemID,
			&i.AddedAt,
			&i.AddedByUserID,
			&i.Excluded,
			&i.Title,
			&i.Author,
			&i.CoverImagePath,
			&i.LibraryID,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetCollectionItemsForDashboard = `-- name: GetCollectionItemsForDashboard :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, ci.excluded FROM media_items mi
INNER JOIN collection_items ci ON ci.media_item_id = mi.id
WHERE ci.collection_id = $1
  AND mi.library_id = $2
ORDER BY ci.added_at DESC
LIMIT $3
`

type GetCollectionItemsForDashboardParams struct {
	CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
	LibraryID    pgtype.UUID `db:"library_id" json:"library_id"`
	Limit        int32       `db:"limit" json:"limit"`
}

type GetCollectionItemsForDashboardRow struct {
	ID                 pgtype.UUID        `db:"id" json:"id"`
	LibraryID          pgtype.UUID        `db:"library_id" json:"library_id"`
	Title              string             `db:"title" json:"title"`
	Author             pgtype.Text        `db:"author" json:"author"`
	Isbn               pgtype.Text        `db:"isbn" json:"isbn"`
	Description        pgtype.Text        `db:"description" json:"description"`
	FilePath           string             `db:"file_path" json:"file_path"`
	FileSize           pgtype.Int8        `db:"file_size" json:"file_size"`
	MimeType           pgtype.Text        `db:"mime_type" json:"mime_type"`
	CoverImagePath     pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text        `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4        `db:"series_number" json:"series_number"`
	Tags               []string           `db:"tags" json:"tags"`
	Asin               pgtype.Text        `db:"asin" json:"asin"`
	DatePublished      pgtype.Date        `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text        `db:"publisher" json:"publisher"`
	Contributors       []string           `db:"contributors" json:"contributors"`
	Language           pgtype.Text        `db:"language" json:"language"`
	Edition            pgtype.Text        `db:"edition" json:"edition"`
	PageCount          pgtype.Int4        `db:"page_count" json:"page_count"`
	Genre              pgtype.Text        `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4        `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text        `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text        `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text        `db:"google_books_id" json:"google_books_id"`
	AddedByAdminID     pgtype.UUID        `db:"added_by_admin_id" json:"added_by_admin_id"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt          pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	FormatGroup        string             `db:"format_group" json:"format_group"`
	FormatMimetype     pgtype.Text        `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable       pgtype.Bool        `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout     pgtype.Bool        `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters    pgtype.Int8        `db:"total_characters" json:"total_characters"`
	ChapterCount       pgtype.Int4        `db:"chapter_count" json:"chapter_count"`
	EntitlementID      pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber     pgtype.Int4        `db:"revision_number" json:"revision_number"`
	KoboContentID      pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	KoboMetadata       []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	TagsSearch         []string           `db:"tags_search" json:"tags_search"`
	ContributorsSearch []string           `db:"contributors_search" json:"contributors_search"`
	FileSha256         pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier      pgtype.Text        `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid            pgtype.Text        `db:"opf_uuid" json:"opf_uuid"`
	HashConfidence     pgtype.Text        `db:"hash_confidence" json:"hash_confidence"`
	Excluded           pgtype.Bool        `db:"excluded" json:"excluded"`
}

func (q *Queries) GetCollectionItemsForDashboard(ctx context.Context, arg GetCollectionItemsForDashboardParams) ([]GetCollectionItemsForDashboardRow, error) {
	rows, err := q.db.Query(ctx, GetCollectionItemsForDashboard, arg.CollectionID, arg.LibraryID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetCollectionItemsForDashboardRow{}
	for rows.Next() {
		var i GetCollectionItemsForDashboardRow
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
			&i.Excluded,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetCollectionWithBookCount = `-- name: GetCollectionWithBookCount :one
SELECT
    c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at,
    COUNT(ci.id) as book_count
FROM collections c
LEFT JOIN collection_items ci ON c.id = ci.collection_id
WHERE c.id = $1
GROUP BY c.id
`

type GetCollectionWithBookCountRow struct {
	ID                 pgtype.UUID        `db:"id" json:"id"`
	UserID             pgtype.UUID        `db:"user_id" json:"user_id"`
	Name               string             `db:"name" json:"name"`
	Description        pgtype.Text        `db:"description" json:"description"`
	Color              pgtype.Text        `db:"color" json:"color"`
	Icon               pgtype.Text        `db:"icon" json:"icon"`
	AutoAssignRules    []byte             `db:"auto_assign_rules" json:"auto_assign_rules"`
	ViewSettings       []byte             `db:"view_settings" json:"view_settings"`
	ShowOnDashboard    pgtype.Bool        `db:"show_on_dashboard" json:"show_on_dashboard"`
	QueryType          pgtype.Text        `db:"query_type" json:"query_type"`
	Priority           pgtype.Int4        `db:"priority" json:"priority"`
	IsSystemCollection pgtype.Bool        `db:"is_system_collection" json:"is_system_collection"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
	BookCount          int64              `db:"book_count" json:"book_count"`
}

// Get collection with book count
func (q *Queries) GetCollectionWithBookCount(ctx context.Context, id pgtype.UUID) (GetCollectionWithBookCountRow, error) {
	row := q.db.QueryRow(ctx, GetCollectionWithBookCount, id)
	var i GetCollectionWithBookCountRow
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.Name,
		&i.Description,
		&i.Color,
		&i.Icon,
		&i.AutoAssignRules,
		&i.ViewSettings,
		&i.ShowOnDashboard,
		&i.QueryType,
		&i.Priority,
		&i.IsSystemCollection,
		&i.CreatedAt,
		&i.BookCount,
	)
	return i, err
}

const GetCollectionsByUser = `-- name: GetCollectionsByUser :many
SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections WHERE user_id = $1 ORDER BY created_at DESC
`

// Get collections by user
func (q *Queries) GetCollectionsByUser(ctx context.Context, userID pgtype.UUID) ([]Collections, error) {
	rows, err := q.db.Query(ctx, GetCollectionsByUser, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []Collections{}
	for rows.Next() {
		var i Collections
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.Name,
			&i.Description,
			&i.Color,
			&i.Icon,
			&i.AutoAssignRules,
			&i.ViewSettings,
			&i.ShowOnDashboard,
			&i.QueryType,
			&i.Priority,
			&i.IsSystemCollection,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetCollectionsForBook = `-- name: GetCollectionsForBook :many
SELECT c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at
FROM collections c
JOIN collection_items ci ON c.id = ci.collection_id
WHERE ci.media_item_id = $1
`

// Get collections for book
func (q *Queries) GetCollectionsForBook(ctx context.Context, mediaItemID pgtype.UUID) ([]Collections, error) {
	rows, err := q.db.Query(ctx, GetCollectionsForBook, mediaItemID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []Collections{}
	for rows.Next() {
		var i Collections
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.Name,
			&i.Description,
			&i.Color,
			&i.Icon,
			&i.AutoAssignRules,
			&i.ViewSettings,
			&i.ShowOnDashboard,
			&i.QueryType,
			&i.Priority,
			&i.IsSystemCollection,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetContinueReadingItems = `-- name: GetContinueReadingItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
INNER JOIN (
    SELECT DISTINCT ON (media_item_id) media_item_id, last_read_at
    FROM reading_progress
    WHERE user_id = $2
      AND percentage > 0
      AND percentage < 1
    ORDER BY media_item_id, last_read_at DESC
) rp ON rp.media_item_id = mi.id
WHERE mi.library_id = $1
ORDER BY rp.last_read_at DESC
LIMIT $3
`

type GetContinueReadingItemsParams struct {
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
	UserID    pgtype.UUID `db:"user_id" json:"user_id"`
	Limit     int32       `db:"limit" json:"limit"`
}

// Smart section queries (for system collections)
func (q *Queries) GetContinueReadingItems(ctx context.Context, arg GetContinueReadingItemsParams) ([]MediaItems, error) {
	rows, err := q.db.Query(ctx, GetContinueReadingItems, arg.LibraryID, arg.UserID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []MediaItems{}
	for rows.Next() {
		var i MediaItems
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetDashboardPreferences = `-- name: GetDashboardPreferences :one

SELECT id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at FROM user_dashboard_preferences
WHERE user_id = $1 AND library_id = $2
`

type GetDashboardPreferencesParams struct {
	UserID    pgtype.UUID `db:"user_id" json:"user_id"`
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}

// ============================================
// CAROUSEL-STYLE DASHBOARD
// ============================================
// Dashboard preferences queries
func (q *Queries) GetDashboardPreferences(ctx context.Context, arg GetDashboardPreferencesParams) (UserDashboardPreferences, error) {
	row := q.db.QueryRow(ctx, GetDashboardPreferences, arg.UserID, arg.LibraryID)
	var i UserDashboardPreferences
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.LibraryID,
		&i.HiddenCollections,
		&i.CollectionOrder,
		&i.ItemsPerSection,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetDevice = `-- name: GetDevice :one
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE id = $1
`

func (q *Queries) GetDevice(ctx context.Context, id pgtype.UUID) (Devices, error) {
	row := q.db.QueryRow(ctx, GetDevice, id)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetDeviceByAuthToken = `-- name: GetDeviceByAuthToken :one
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE auth_token = $1
`

func (q *Queries) GetDeviceByAuthToken(ctx context.Context, authToken string) (Devices, error) {
	row := q.db.QueryRow(ctx, GetDeviceByAuthToken, authToken)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetDeviceByIdentifier = `-- name: GetDeviceByIdentifier :one
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE device_identifier = $1
`

func (q *Queries) GetDeviceByIdentifier(ctx context.Context, deviceIdentifier string) (Devices, error) {
	row := q.db.QueryRow(ctx, GetDeviceByIdentifier, deviceIdentifier)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetDeviceCatalogByBookhoardUUID = `-- name: GetDeviceCatalogByBookhoardUUID :one
SELECT id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method FROM device_catalogs WHERE device_id = $1 AND bookhoard_uuid = $2
`

type GetDeviceCatalogByBookhoardUUIDParams struct {
	DeviceID      pgtype.UUID `db:"device_id" json:"device_id"`
	BookhoardUuid pgtype.UUID `db:"bookhoard_uuid" json:"bookhoard_uuid"`
}

// Get device catalog by Bookhoard UUID
func (q *Queries) GetDeviceCatalogByBookhoardUUID(ctx context.Context, arg GetDeviceCatalogByBookhoardUUIDParams) (DeviceCatalogs, error) {
	row := q.db.QueryRow(ctx, GetDeviceCatalogByBookhoardUUID, arg.DeviceID, arg.BookhoardUuid)
	var i DeviceCatalogs
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.BookhoardUuid,
		&i.KoboContentID,
		&i.ContentIDType,
		&i.Available,
		&i.DeliveryDate,
		&i.DeliveryMethod,
	)
	return i, err
}

const GetDeviceCatalogByKoboContentId = `-- name: GetDeviceCatalogByKoboContentId :one
SELECT id, device_id, media_item_id, bookhoard_uuid, kobo_content_id, content_id_type, available, delivery_date, delivery_method FROM device_catalogs WHERE kobo_content_id = $1
`

// Get device catalog by Kobo ContentId
func (q *Queries) GetDeviceCatalogByKoboContentId(ctx context.Context, koboContentID string) (DeviceCatalogs, error) {
	row := q.db.QueryRow(ctx, GetDeviceCatalogByKoboContentId, koboContentID)
	var i DeviceCatalogs
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.BookhoardUuid,
		&i.KoboContentID,
		&i.ContentIDType,
		&i.Available,
		&i.DeliveryDate,
		&i.DeliveryMethod,
	)
	return i, err
}

const GetDeviceCatalogEntries = `-- name: GetDeviceCatalogEntries :many
SELECT dc.id, dc.device_id, dc.media_item_id, dc.bookhoard_uuid, dc.kobo_content_id, dc.content_id_type, dc.available, dc.delivery_date, dc.delivery_method, mi.title, mi.author
FROM device_catalogs dc
JOIN media_items mi ON dc.media_item_id = mi.id
WHERE dc.device_id = $1 AND dc.available = true
ORDER BY dc.delivery_date DESC
`

type GetDeviceCatalogEntriesRow struct {
	ID             pgtype.UUID        `db:"id" json:"id"`
	DeviceID       pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID    pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	BookhoardUuid  pgtype.UUID        `db:"bookhoard_uuid" json:"bookhoard_uuid"`
	KoboContentID  string             `db:"kobo_content_id" json:"kobo_content_id"`
	ContentIDType  pgtype.Text        `db:"content_id_type" json:"content_id_type"`
	Available      pgtype.Bool        `db:"available" json:"available"`
	DeliveryDate   pgtype.Timestamptz `db:"delivery_date" json:"delivery_date"`
	DeliveryMethod pgtype.Text        `db:"delivery_method" json:"delivery_method"`
	Title          string             `db:"title" json:"title"`
	Author         pgtype.Text        `db:"author" json:"author"`
}

// Get device catalog entries
func (q *Queries) GetDeviceCatalogEntries(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceCatalogEntriesRow, error) {
	rows, err := q.db.Query(ctx, GetDeviceCatalogEntries, deviceID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetDeviceCatalogEntriesRow{}
	for rows.Next() {
		var i GetDeviceCatalogEntriesRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.BookhoardUuid,
			&i.KoboContentID,
			&i.ContentIDType,
			&i.Available,
			&i.DeliveryDate,
			&i.DeliveryMethod,
			&i.Title,
			&i.Author,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetDeviceFileAlias = `-- name: GetDeviceFileAlias :one
SELECT id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at FROM device_file_aliases WHERE device_id = $1 AND file_path = $2
`

type GetDeviceFileAliasParams struct {
	DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
	FilePath string      `db:"file_path" json:"file_path"`
}

// Get device file alias
func (q *Queries) GetDeviceFileAlias(ctx context.Context, arg GetDeviceFileAliasParams) (DeviceFileAliases, error) {
	row := q.db.QueryRow(ctx, GetDeviceFileAlias, arg.DeviceID, arg.FilePath)
	var i DeviceFileAliases
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.DeviceID,
		&i.FilePath,
		&i.FileSha256,
		&i.ConfidenceScore,
		&i.LastSeenAt,
	)
	return i, err
}

const GetDeviceFileAliasBySHA256 = `-- name: GetDeviceFileAliasBySHA256 :one
SELECT dfa.id, dfa.media_item_id, dfa.device_id, dfa.file_path, dfa.file_sha256, dfa.confidence_score, dfa.last_seen_at, mi.title, mi.author
FROM device_file_aliases dfa
JOIN media_items mi ON dfa.media_item_id = mi.id
WHERE dfa.file_sha256 = $1
`

type GetDeviceFileAliasBySHA256Row struct {
	ID              pgtype.UUID        `db:"id" json:"id"`
	MediaItemID     pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	DeviceID        pgtype.UUID        `db:"device_id" json:"device_id"`
	FilePath        string             `db:"file_path" json:"file_path"`
	FileSha256      pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	ConfidenceScore pgtype.Float8      `db:"confidence_score" json:"confidence_score"`
	LastSeenAt      pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"`
	Title           string             `db:"title" json:"title"`
	Author          pgtype.Text        `db:"author" json:"author"`
}

// Get device file alias by SHA-256
func (q *Queries) GetDeviceFileAliasBySHA256(ctx context.Context, fileSha256 pgtype.Text) (GetDeviceFileAliasBySHA256Row, error) {
	row := q.db.QueryRow(ctx, GetDeviceFileAliasBySHA256, fileSha256)
	var i GetDeviceFileAliasBySHA256Row
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.DeviceID,
		&i.FilePath,
		&i.FileSha256,
		&i.ConfidenceScore,
		&i.LastSeenAt,
		&i.Title,
		&i.Author,
	)
	return i, err
}

const GetDeviceFileAliasesByDevice = `-- name: GetDeviceFileAliasesByDevice :many
SELECT dfa.id, dfa.media_item_id, dfa.device_id, dfa.file_path, dfa.file_sha256, dfa.confidence_score, dfa.last_seen_at, mi.title, mi.author
FROM device_file_aliases dfa
JOIN media_items mi ON dfa.media_item_id = mi.id
WHERE dfa.device_id = $1
ORDER BY dfa.last_seen_at DESC
`

type GetDeviceFileAliasesByDeviceRow struct {
	ID              pgtype.UUID        `db:"id" json:"id"`
	MediaItemID     pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	DeviceID        pgtype.UUID        `db:"device_id" json:"device_id"`
	FilePath        string             `db:"file_path" json:"file_path"`
	FileSha256      pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	ConfidenceScore pgtype.Float8      `db:"confidence_score" json:"confidence_score"`
	LastSeenAt      pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"`
	Title           string             `db:"title" json:"title"`
	Author          pgtype.Text        `db:"author" json:"author"`
}

// Get device file aliases by device
func (q *Queries) GetDeviceFileAliasesByDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceFileAliasesByDeviceRow, error) {
	rows, err := q.db.Query(ctx, GetDeviceFileAliasesByDevice, deviceID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetDeviceFileAliasesByDeviceRow{}
	for rows.Next() {
		var i GetDeviceFileAliasesByDeviceRow
		if err := rows.Scan(
			&i.ID,
			&i.MediaItemID,
			&i.DeviceID,
			&i.FilePath,
			&i.FileSha256,
			&i.ConfidenceScore,
			&i.LastSeenAt,
			&i.Title,
			&i.Author,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetDeviceShelfMapping = `-- name: GetDeviceShelfMapping :one
SELECT id, collection_id, device_id, device_shelf_name, sync_direction, created_at FROM device_shelf_mappings WHERE device_id = $1 AND collection_id = $2
`

type GetDeviceShelfMappingParams struct {
	DeviceID     pgtype.UUID `db:"device_id" json:"device_id"`
	CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
}

// Get device shelf mapping
func (q *Queries) GetDeviceShelfMapping(ctx context.Context, arg GetDeviceShelfMappingParams) (DeviceShelfMappings, error) {
	row := q.db.QueryRow(ctx, GetDeviceShelfMapping, arg.DeviceID, arg.CollectionID)
	var i DeviceShelfMappings
	err := row.Scan(
		&i.ID,
		&i.CollectionID,
		&i.DeviceID,
		&i.DeviceShelfName,
		&i.SyncDirection,
		&i.CreatedAt,
	)
	return i, err
}

const GetDeviceShelfMappings = `-- name: GetDeviceShelfMappings :many
SELECT dsm.id, dsm.collection_id, dsm.device_id, dsm.device_shelf_name, dsm.sync_direction, dsm.created_at, c.name as collection_name, c.icon as collection_icon
FROM device_shelf_mappings dsm
JOIN collections c ON dsm.collection_id = c.id
WHERE dsm.device_id = $1
`

type GetDeviceShelfMappingsRow struct {
	ID              pgtype.UUID        `db:"id" json:"id"`
	CollectionID    pgtype.UUID        `db:"collection_id" json:"collection_id"`
	DeviceID        pgtype.UUID        `db:"device_id" json:"device_id"`
	DeviceShelfName pgtype.Text        `db:"device_shelf_name" json:"device_shelf_name"`
	SyncDirection   pgtype.Text        `db:"sync_direction" json:"sync_direction"`
	CreatedAt       pgtype.Timestamptz `db:"created_at" json:"created_at"`
	CollectionName  string             `db:"collection_name" json:"collection_name"`
	CollectionIcon  pgtype.Text        `db:"collection_icon" json:"collection_icon"`
}

// Get device shelf mappings
func (q *Queries) GetDeviceShelfMappings(ctx context.Context, deviceID pgtype.UUID) ([]GetDeviceShelfMappingsRow, error) {
	rows, err := q.db.Query(ctx, GetDeviceShelfMappings, deviceID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetDeviceShelfMappingsRow{}
	for rows.Next() {
		var i GetDeviceShelfMappingsRow
		if err := rows.Scan(
			&i.ID,
			&i.CollectionID,
			&i.DeviceID,
			&i.DeviceShelfName,
			&i.SyncDirection,
			&i.CreatedAt,
			&i.CollectionName,
			&i.CollectionIcon,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetFailedSyncQueueItems = `-- name: GetFailedSyncQueueItems :many
SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue
WHERE status = 'failed' AND attempts < max_attempts
ORDER BY priority ASC, created_at ASC
LIMIT $1
`

func (q *Queries) GetFailedSyncQueueItems(ctx context.Context, limit int32) ([]SyncQueue, error) {
	rows, err := q.db.Query(ctx, GetFailedSyncQueueItems, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []SyncQueue{}
	for rows.Next() {
		var i SyncQueue
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.SyncType,
			&i.SyncData,
			&i.Priority,
			&i.Attempts,
			&i.MaxAttempts,
			&i.Status,
			&i.ErrorMessage,
			&i.CreatedAt,
			&i.ProcessedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetKoboEntitlementByContentId = `-- name: GetKoboEntitlementByContentId :one
SELECT ke.id, ke.device_id, ke.media_item_id, ke.entitlement_id, ke.content_id, ke.revision_number, ke.purchase_date, ke.accession_date, ke.book_status, ke.sync_status, ke.kobo_metadata, ke.created_at, ke.updated_at, mi.title, mi.author, mi.file_path
FROM kobo_entitlements ke
JOIN media_items mi ON ke.media_item_id = mi.id
WHERE ke.device_id = $1 AND ke.content_id = $2
`

type GetKoboEntitlementByContentIdParams struct {
	DeviceID  pgtype.UUID `db:"device_id" json:"device_id"`
	ContentID string      `db:"content_id" json:"content_id"`
}

type GetKoboEntitlementByContentIdRow struct {
	ID             pgtype.UUID        `db:"id" json:"id"`
	DeviceID       pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID    pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	EntitlementID  string             `db:"entitlement_id" json:"entitlement_id"`
	ContentID      string             `db:"content_id" json:"content_id"`
	RevisionNumber pgtype.Int4        `db:"revision_number" json:"revision_number"`
	PurchaseDate   pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"`
	AccessionDate  pgtype.Timestamptz `db:"accession_date" json:"accession_date"`
	BookStatus     pgtype.Text        `db:"book_status" json:"book_status"`
	SyncStatus     pgtype.Text        `db:"sync_status" json:"sync_status"`
	KoboMetadata   []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	CreatedAt      pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt      pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	Title          string             `db:"title" json:"title"`
	Author         pgtype.Text        `db:"author" json:"author"`
	FilePath       string             `db:"file_path" json:"file_path"`
}

func (q *Queries) GetKoboEntitlementByContentId(ctx context.Context, arg GetKoboEntitlementByContentIdParams) (GetKoboEntitlementByContentIdRow, error) {
	row := q.db.QueryRow(ctx, GetKoboEntitlementByContentId, arg.DeviceID, arg.ContentID)
	var i GetKoboEntitlementByContentIdRow
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.EntitlementID,
		&i.ContentID,
		&i.RevisionNumber,
		&i.PurchaseDate,
		&i.AccessionDate,
		&i.BookStatus,
		&i.SyncStatus,
		&i.KoboMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.Title,
		&i.Author,
		&i.FilePath,
	)
	return i, err
}

const GetKoboEntitlementByEntitlementId = `-- name: GetKoboEntitlementByEntitlementId :one
SELECT ke.id, ke.device_id, ke.media_item_id, ke.entitlement_id, ke.content_id, ke.revision_number, ke.purchase_date, ke.accession_date, ke.book_status, ke.sync_status, ke.kobo_metadata, ke.created_at, ke.updated_at, mi.title, mi.author, mi.file_path
FROM kobo_entitlements ke
JOIN media_items mi ON ke.media_item_id = mi.id
WHERE ke.device_id = $1 AND ke.entitlement_id = $2
`

type GetKoboEntitlementByEntitlementIdParams struct {
	DeviceID      pgtype.UUID `db:"device_id" json:"device_id"`
	EntitlementID string      `db:"entitlement_id" json:"entitlement_id"`
}

type GetKoboEntitlementByEntitlementIdRow struct {
	ID             pgtype.UUID        `db:"id" json:"id"`
	DeviceID       pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID    pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	EntitlementID  string             `db:"entitlement_id" json:"entitlement_id"`
	ContentID      string             `db:"content_id" json:"content_id"`
	RevisionNumber pgtype.Int4        `db:"revision_number" json:"revision_number"`
	PurchaseDate   pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"`
	AccessionDate  pgtype.Timestamptz `db:"accession_date" json:"accession_date"`
	BookStatus     pgtype.Text        `db:"book_status" json:"book_status"`
	SyncStatus     pgtype.Text        `db:"sync_status" json:"sync_status"`
	KoboMetadata   []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	CreatedAt      pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt      pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	Title          string             `db:"title" json:"title"`
	Author         pgtype.Text        `db:"author" json:"author"`
	FilePath       string             `db:"file_path" json:"file_path"`
}

func (q *Queries) GetKoboEntitlementByEntitlementId(ctx context.Context, arg GetKoboEntitlementByEntitlementIdParams) (GetKoboEntitlementByEntitlementIdRow, error) {
	row := q.db.QueryRow(ctx, GetKoboEntitlementByEntitlementId, arg.DeviceID, arg.EntitlementID)
	var i GetKoboEntitlementByEntitlementIdRow
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.EntitlementID,
		&i.ContentID,
		&i.RevisionNumber,
		&i.PurchaseDate,
		&i.AccessionDate,
		&i.BookStatus,
		&i.SyncStatus,
		&i.KoboMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.Title,
		&i.Author,
		&i.FilePath,
	)
	return i, err
}

const GetKoboEntitlementsForDevice = `-- name: GetKoboEntitlementsForDevice :many
SELECT ke.id, ke.device_id, ke.media_item_id, ke.entitlement_id, ke.content_id, ke.revision_number, ke.purchase_date, ke.accession_date, ke.book_status, ke.sync_status, ke.kobo_metadata, ke.created_at, ke.updated_at, mi.title, mi.author, mi.file_path
FROM kobo_entitlements ke
JOIN media_items mi ON ke.media_item_id = mi.id
WHERE ke.device_id = $1
ORDER BY ke.accession_date DESC
`

type GetKoboEntitlementsForDeviceRow struct {
	ID             pgtype.UUID        `db:"id" json:"id"`
	DeviceID       pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID    pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	EntitlementID  string             `db:"entitlement_id" json:"entitlement_id"`
	ContentID      string             `db:"content_id" json:"content_id"`
	RevisionNumber pgtype.Int4        `db:"revision_number" json:"revision_number"`
	PurchaseDate   pgtype.Timestamptz `db:"purchase_date" json:"purchase_date"`
	AccessionDate  pgtype.Timestamptz `db:"accession_date" json:"accession_date"`
	BookStatus     pgtype.Text        `db:"book_status" json:"book_status"`
	SyncStatus     pgtype.Text        `db:"sync_status" json:"sync_status"`
	KoboMetadata   []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	CreatedAt      pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt      pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	Title          string             `db:"title" json:"title"`
	Author         pgtype.Text        `db:"author" json:"author"`
	FilePath       string             `db:"file_path" json:"file_path"`
}

func (q *Queries) GetKoboEntitlementsForDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetKoboEntitlementsForDeviceRow, error) {
	rows, err := q.db.Query(ctx, GetKoboEntitlementsForDevice, deviceID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetKoboEntitlementsForDeviceRow{}
	for rows.Next() {
		var i GetKoboEntitlementsForDeviceRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.EntitlementID,
			&i.ContentID,
			&i.RevisionNumber,
			&i.PurchaseDate,
			&i.AccessionDate,
			&i.BookStatus,
			&i.SyncStatus,
			&i.KoboMetadata,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.Title,
			&i.Author,
			&i.FilePath,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetKoboShelfBookCount = `-- name: GetKoboShelfBookCount :one
SELECT COUNT(*) as book_count
FROM kobo_shelves
WHERE device_id = $1
`

func (q *Queries) GetKoboShelfBookCount(ctx context.Context, deviceID pgtype.UUID) (int64, error) {
	row := q.db.QueryRow(ctx, GetKoboShelfBookCount, deviceID)
	var book_count int64
	err := row.Scan(&book_count)
	return book_count, err
}

const GetKoboShelfBooks = `-- name: GetKoboShelfBooks :many
SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author, mi.file_path, mi.mime_type, mi.entitlement_id, mi.kobo_content_id, mi.revision_number
FROM kobo_shelves ks
JOIN media_items mi ON ks.media_item_id = mi.id
WHERE ks.device_id = $1
ORDER BY ks.shelf_position ASC, ks.added_at ASC
`

type GetKoboShelfBooksRow struct {
	ID                   pgtype.UUID        `db:"id" json:"id"`
	DeviceID             pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID          pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	ShelfName            pgtype.Text        `db:"shelf_name" json:"shelf_name"`
	ShelfPosition        pgtype.Int4        `db:"shelf_position" json:"shelf_position"`
	AddedAt              pgtype.Timestamptz `db:"added_at" json:"added_at"`
	LastSyncedAt         pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"`
	CollectionID         pgtype.UUID        `db:"collection_id" json:"collection_id"`
	PositionInCollection pgtype.Int4        `db:"position_in_collection" json:"position_in_collection"`
	Title                string             `db:"title" json:"title"`
	Author               pgtype.Text        `db:"author" json:"author"`
	FilePath             string             `db:"file_path" json:"file_path"`
	MimeType             pgtype.Text        `db:"mime_type" json:"mime_type"`
	EntitlementID        pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	KoboContentID        pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	RevisionNumber       pgtype.Int4        `db:"revision_number" json:"revision_number"`
}

func (q *Queries) GetKoboShelfBooks(ctx context.Context, deviceID pgtype.UUID) ([]GetKoboShelfBooksRow, error) {
	rows, err := q.db.Query(ctx, GetKoboShelfBooks, deviceID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetKoboShelfBooksRow{}
	for rows.Next() {
		var i GetKoboShelfBooksRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.ShelfName,
			&i.ShelfPosition,
			&i.AddedAt,
			&i.LastSyncedAt,
			&i.CollectionID,
			&i.PositionInCollection,
			&i.Title,
			&i.Author,
			&i.FilePath,
			&i.MimeType,
			&i.EntitlementID,
			&i.KoboContentID,
			&i.RevisionNumber,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetKoboShelfBooksByShelfName = `-- name: GetKoboShelfBooksByShelfName :many
SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author, mi.file_path, mi.mime_type, mi.entitlement_id, mi.kobo_content_id, mi.revision_number
FROM kobo_shelves ks
JOIN media_items mi ON ks.media_item_id = mi.id
WHERE ks.device_id = $1 AND ks.shelf_name = $2
ORDER BY ks.shelf_position ASC, ks.added_at ASC
`

type GetKoboShelfBooksByShelfNameParams struct {
	DeviceID  pgtype.UUID `db:"device_id" json:"device_id"`
	ShelfName pgtype.Text `db:"shelf_name" json:"shelf_name"`
}

type GetKoboShelfBooksByShelfNameRow struct {
	ID                   pgtype.UUID        `db:"id" json:"id"`
	DeviceID             pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID          pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	ShelfName            pgtype.Text        `db:"shelf_name" json:"shelf_name"`
	ShelfPosition        pgtype.Int4        `db:"shelf_position" json:"shelf_position"`
	AddedAt              pgtype.Timestamptz `db:"added_at" json:"added_at"`
	LastSyncedAt         pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"`
	CollectionID         pgtype.UUID        `db:"collection_id" json:"collection_id"`
	PositionInCollection pgtype.Int4        `db:"position_in_collection" json:"position_in_collection"`
	Title                string             `db:"title" json:"title"`
	Author               pgtype.Text        `db:"author" json:"author"`
	FilePath             string             `db:"file_path" json:"file_path"`
	MimeType             pgtype.Text        `db:"mime_type" json:"mime_type"`
	EntitlementID        pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	KoboContentID        pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	RevisionNumber       pgtype.Int4        `db:"revision_number" json:"revision_number"`
}

func (q *Queries) GetKoboShelfBooksByShelfName(ctx context.Context, arg GetKoboShelfBooksByShelfNameParams) ([]GetKoboShelfBooksByShelfNameRow, error) {
	rows, err := q.db.Query(ctx, GetKoboShelfBooksByShelfName, arg.DeviceID, arg.ShelfName)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetKoboShelfBooksByShelfNameRow{}
	for rows.Next() {
		var i GetKoboShelfBooksByShelfNameRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.ShelfName,
			&i.ShelfPosition,
			&i.AddedAt,
			&i.LastSyncedAt,
			&i.CollectionID,
			&i.PositionInCollection,
			&i.Title,
			&i.Author,
			&i.FilePath,
			&i.MimeType,
			&i.EntitlementID,
			&i.KoboContentID,
			&i.RevisionNumber,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetKoboShelvesByCollection = `-- name: GetKoboShelvesByCollection :many
SELECT ks.id, ks.device_id, ks.media_item_id, ks.shelf_name, ks.shelf_position, ks.added_at, ks.last_synced_at, ks.collection_id, ks.position_in_collection, mi.title, mi.author
FROM kobo_shelves ks
JOIN media_items mi ON ks.media_item_id = mi.id
WHERE ks.device_id = $1 AND ks.collection_id = $2
ORDER BY ks.position_in_collection ASC, ks.shelf_position ASC
`

type GetKoboShelvesByCollectionParams struct {
	DeviceID     pgtype.UUID `db:"device_id" json:"device_id"`
	CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
}

type GetKoboShelvesByCollectionRow struct {
	ID                   pgtype.UUID        `db:"id" json:"id"`
	DeviceID             pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID          pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	ShelfName            pgtype.Text        `db:"shelf_name" json:"shelf_name"`
	ShelfPosition        pgtype.Int4        `db:"shelf_position" json:"shelf_position"`
	AddedAt              pgtype.Timestamptz `db:"added_at" json:"added_at"`
	LastSyncedAt         pgtype.Timestamptz `db:"last_synced_at" json:"last_synced_at"`
	CollectionID         pgtype.UUID        `db:"collection_id" json:"collection_id"`
	PositionInCollection pgtype.Int4        `db:"position_in_collection" json:"position_in_collection"`
	Title                string             `db:"title" json:"title"`
	Author               pgtype.Text        `db:"author" json:"author"`
}

// Get Kobo shelves by collection
func (q *Queries) GetKoboShelvesByCollection(ctx context.Context, arg GetKoboShelvesByCollectionParams) ([]GetKoboShelvesByCollectionRow, error) {
	rows, err := q.db.Query(ctx, GetKoboShelvesByCollection, arg.DeviceID, arg.CollectionID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetKoboShelvesByCollectionRow{}
	for rows.Next() {
		var i GetKoboShelvesByCollectionRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.ShelfName,
			&i.ShelfPosition,
			&i.AddedAt,
			&i.LastSyncedAt,
			&i.CollectionID,
			&i.PositionInCollection,
			&i.Title,
			&i.Author,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetLibrary = `-- name: GetLibrary :one
SELECT l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at, lt.name as type_name, lt.description as type_description
FROM libraries l
JOIN library_types lt ON l.library_type_id = lt.id
WHERE l.id = $1
`

type GetLibraryRow struct {
	ID               pgtype.UUID        `db:"id" json:"id"`
	Name             string             `db:"name" json:"name"`
	Description      pgtype.Text        `db:"description" json:"description"`
	LibraryTypeID    pgtype.UUID        `db:"library_type_id" json:"library_type_id"`
	CreatedByAdminID pgtype.UUID        `db:"created_by_admin_id" json:"created_by_admin_id"`
	CreatedAt        pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	TypeName         string             `db:"type_name" json:"type_name"`
	TypeDescription  pgtype.Text        `db:"type_description" json:"type_description"`
}

func (q *Queries) GetLibrary(ctx context.Context, id pgtype.UUID) (GetLibraryRow, error) {
	row := q.db.QueryRow(ctx, GetLibrary, id)
	var i GetLibraryRow
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.Description,
		&i.LibraryTypeID,
		&i.CreatedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.TypeName,
		&i.TypeDescription,
	)
	return i, err
}

const GetLibraryByFolder = `-- name: GetLibraryByFolder :one
SELECT lf.library_id, l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at FROM library_folders lf
JOIN libraries l ON lf.library_id = l.id
WHERE lf.folder_path = $1
`

type GetLibraryByFolderRow struct {
	LibraryID        pgtype.UUID        `db:"library_id" json:"library_id"`
	ID               pgtype.UUID        `db:"id" json:"id"`
	Name             string             `db:"name" json:"name"`
	Description      pgtype.Text        `db:"description" json:"description"`
	LibraryTypeID    pgtype.UUID        `db:"library_type_id" json:"library_type_id"`
	CreatedByAdminID pgtype.UUID        `db:"created_by_admin_id" json:"created_by_admin_id"`
	CreatedAt        pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}

func (q *Queries) GetLibraryByFolder(ctx context.Context, folderPath string) (GetLibraryByFolderRow, error) {
	row := q.db.QueryRow(ctx, GetLibraryByFolder, folderPath)
	var i GetLibraryByFolderRow
	err := row.Scan(
		&i.LibraryID,
		&i.ID,
		&i.Name,
		&i.Description,
		&i.LibraryTypeID,
		&i.CreatedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetLibraryFolders = `-- name: GetLibraryFolders :many
SELECT id, library_id, folder_path, created_at FROM library_folders WHERE library_id = $1 ORDER BY created_at
`

func (q *Queries) GetLibraryFolders(ctx context.Context, libraryID pgtype.UUID) ([]LibraryFolders, error) {
	rows, err := q.db.Query(ctx, GetLibraryFolders, libraryID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []LibraryFolders{}
	for rows.Next() {
		var i LibraryFolders
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.FolderPath,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetLibraryItems = `-- name: GetLibraryItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE mi.library_id = $1
ORDER BY mi.created_at DESC
`

func (q *Queries) GetLibraryItems(ctx context.Context, libraryID pgtype.UUID) ([]MediaItems, error) {
	rows, err := q.db.Query(ctx, GetLibraryItems, libraryID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []MediaItems{}
	for rows.Next() {
		var i MediaItems
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetLibraryType = `-- name: GetLibraryType :one
SELECT id, name, description, allowed_extensions, created_at FROM library_types WHERE id = $1
`

func (q *Queries) GetLibraryType(ctx context.Context, id pgtype.UUID) (LibraryTypes, error) {
	row := q.db.QueryRow(ctx, GetLibraryType, id)
	var i LibraryTypes
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.Description,
		&i.AllowedExtensions,
		&i.CreatedAt,
	)
	return i, err
}

const GetLibraryTypeByName = `-- name: GetLibraryTypeByName :one
SELECT id, name, description, allowed_extensions, created_at FROM library_types WHERE name = $1
`

func (q *Queries) GetLibraryTypeByName(ctx context.Context, name string) (LibraryTypes, error) {
	row := q.db.QueryRow(ctx, GetLibraryTypeByName, name)
	var i LibraryTypes
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.Description,
		&i.AllowedExtensions,
		&i.CreatedAt,
	)
	return i, err
}

const GetLibraryTypes = `-- name: GetLibraryTypes :many
SELECT id, name, description, allowed_extensions, created_at FROM library_types ORDER BY name
`

// Library Types queries
func (q *Queries) GetLibraryTypes(ctx context.Context) ([]LibraryTypes, error) {
	rows, err := q.db.Query(ctx, GetLibraryTypes)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []LibraryTypes{}
	for rows.Next() {
		var i LibraryTypes
		if err := rows.Scan(
			&i.ID,
			&i.Name,
			&i.Description,
			&i.AllowedExtensions,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetLibraryVisibility = `-- name: GetLibraryVisibility :one
SELECT id, user_id, library_id, is_visible, created_at, updated_at FROM library_visibility WHERE user_id = $1 AND library_id = $2
`

type GetLibraryVisibilityParams struct {
	UserID    pgtype.UUID `db:"user_id" json:"user_id"`
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}

func (q *Queries) GetLibraryVisibility(ctx context.Context, arg GetLibraryVisibilityParams) (LibraryVisibility, error) {
	row := q.db.QueryRow(ctx, GetLibraryVisibility, arg.UserID, arg.LibraryID)
	var i LibraryVisibility
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.LibraryID,
		&i.IsVisible,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetMediaHighlight = `-- name: GetMediaHighlight :one
SELECT id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data FROM media_highlights WHERE id = $1
`

func (q *Queries) GetMediaHighlight(ctx context.Context, id pgtype.UUID) (MediaHighlights, error) {
	row := q.db.QueryRow(ctx, GetMediaHighlight, id)
	var i MediaHighlights
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.SelectionText,
		&i.StartPosition,
		&i.EndPosition,
		&i.Color,
		&i.NoteID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PercentageStart,
		&i.PercentageEnd,
		&i.CharacterStart,
		&i.CharacterEnd,
		&i.EpubcfiStart,
		&i.EpubcfiEnd,
		&i.ChapterReference,
		&i.ParagraphStart,
		&i.ParagraphEnd,
		&i.PanelNumber,
		&i.DeviceSyncData,
	)
	return i, err
}

const GetMediaHighlights = `-- name: GetMediaHighlights :many
SELECT id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data FROM media_highlights WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC
`

type GetMediaHighlightsParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

func (q *Queries) GetMediaHighlights(ctx context.Context, arg GetMediaHighlightsParams) ([]MediaHighlights, error) {
	rows, err := q.db.Query(ctx, GetMediaHighlights, arg.MediaItemID, arg.UserID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []MediaHighlights{}
	for rows.Next() {
		var i MediaHighlights
		if err := rows.Scan(
			&i.ID,
			&i.MediaItemID,
			&i.UserID,
			&i.SelectionText,
			&i.StartPosition,
			&i.EndPosition,
			&i.Color,
			&i.NoteID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.PercentageStart,
			&i.PercentageEnd,
			&i.CharacterStart,
			&i.CharacterEnd,
			&i.EpubcfiStart,
			&i.EpubcfiEnd,
			&i.ChapterReference,
			&i.ParagraphStart,
			&i.ParagraphEnd,
			&i.PanelNumber,
			&i.DeviceSyncData,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetMediaItem = `-- name: GetMediaItem :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE id = $1
`

func (q *Queries) GetMediaItem(ctx context.Context, id pgtype.UUID) (MediaItems, error) {
	row := q.db.QueryRow(ctx, GetMediaItem, id)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const GetMediaItemByFilePath = `-- name: GetMediaItemByFilePath :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 AND library_id = $2
`

type GetMediaItemByFilePathParams struct {
	FilePath  string      `db:"file_path" json:"file_path"`
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
}

func (q *Queries) GetMediaItemByFilePath(ctx context.Context, arg GetMediaItemByFilePathParams) (MediaItems, error) {
	row := q.db.QueryRow(ctx, GetMediaItemByFilePath, arg.FilePath, arg.LibraryID)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const GetMediaItemByFilePathAnyLibrary = `-- name: GetMediaItemByFilePathAnyLibrary :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1 LIMIT 1
`

func (q *Queries) GetMediaItemByFilePathAnyLibrary(ctx context.Context, filePath string) (MediaItems, error) {
	row := q.db.QueryRow(ctx, GetMediaItemByFilePathAnyLibrary, filePath)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const GetMediaItemByFilePathForSync = `-- name: GetMediaItemByFilePathForSync :one

SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_path = $1
`

// ============================================
// KOREADER SYNC PROTOCOL
// ============================================
func (q *Queries) GetMediaItemByFilePathForSync(ctx context.Context, filePath string) (MediaItems, error) {
	row := q.db.QueryRow(ctx, GetMediaItemByFilePathForSync, filePath)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const GetMediaItemByKoboContentId = `-- name: GetMediaItemByKoboContentId :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE kobo_content_id = $1
`

func (q *Queries) GetMediaItemByKoboContentId(ctx context.Context, koboContentID pgtype.Text) (MediaItems, error) {
	row := q.db.QueryRow(ctx, GetMediaItemByKoboContentId, koboContentID)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const GetMediaItemByOPFIdentifier = `-- name: GetMediaItemByOPFIdentifier :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_identifier = $1
`

// Get media item by OPF identifier
func (q *Queries) GetMediaItemByOPFIdentifier(ctx context.Context, opfIdentifier pgtype.Text) (MediaItems, error) {
	row := q.db.QueryRow(ctx, GetMediaItemByOPFIdentifier, opfIdentifier)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const GetMediaItemByOPFUUID = `-- name: GetMediaItemByOPFUUID :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE opf_uuid = $1
`

// Get media item by OPF UUID
func (q *Queries) GetMediaItemByOPFUUID(ctx context.Context, opfUuid pgtype.Text) (MediaItems, error) {
	row := q.db.QueryRow(ctx, GetMediaItemByOPFUUID, opfUuid)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const GetMediaItemBySHA256 = `-- name: GetMediaItemBySHA256 :one
SELECT id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence FROM media_items WHERE file_sha256 = $1
`

// Get media item by SHA-256 hash
func (q *Queries) GetMediaItemBySHA256(ctx context.Context, fileSha256 pgtype.Text) (MediaItems, error) {
	row := q.db.QueryRow(ctx, GetMediaItemBySHA256, fileSha256)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const GetMediaItemFormatBySHA256 = `-- name: GetMediaItemFormatBySHA256 :one
SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE file_sha256 = $1
`

// Get media item format by SHA-256
func (q *Queries) GetMediaItemFormatBySHA256(ctx context.Context, fileSha256 pgtype.Text) (MediaItemFormats, error) {
	row := q.db.QueryRow(ctx, GetMediaItemFormatBySHA256, fileSha256)
	var i MediaItemFormats
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.FormatType,
		&i.FilePath,
		&i.FileSha256,
		&i.FileSizeBytes,
		&i.MimeType,
		&i.CreatedAt,
		&i.ConvertedFromFormatID,
	)
	return i, err
}

const GetMediaItemFormatByType = `-- name: GetMediaItemFormatByType :one
SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE media_item_id = $1 AND format_type = $2
`

type GetMediaItemFormatByTypeParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	FormatType  string      `db:"format_type" json:"format_type"`
}

// Get media item format by type
func (q *Queries) GetMediaItemFormatByType(ctx context.Context, arg GetMediaItemFormatByTypeParams) (MediaItemFormats, error) {
	row := q.db.QueryRow(ctx, GetMediaItemFormatByType, arg.MediaItemID, arg.FormatType)
	var i MediaItemFormats
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.FormatType,
		&i.FilePath,
		&i.FileSha256,
		&i.FileSizeBytes,
		&i.MimeType,
		&i.CreatedAt,
		&i.ConvertedFromFormatID,
	)
	return i, err
}

const GetMediaItemFormats = `-- name: GetMediaItemFormats :many
SELECT id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id FROM media_item_formats WHERE media_item_id = $1
`

// Get media item formats
func (q *Queries) GetMediaItemFormats(ctx context.Context, mediaItemID pgtype.UUID) ([]MediaItemFormats, error) {
	rows, err := q.db.Query(ctx, GetMediaItemFormats, mediaItemID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []MediaItemFormats{}
	for rows.Next() {
		var i MediaItemFormats
		if err := rows.Scan(
			&i.ID,
			&i.MediaItemID,
			&i.FormatType,
			&i.FilePath,
			&i.FileSha256,
			&i.FileSizeBytes,
			&i.MimeType,
			&i.CreatedAt,
			&i.ConvertedFromFormatID,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetMediaNote = `-- name: GetMediaNote :one
SELECT id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data FROM media_notes WHERE id = $1
`

func (q *Queries) GetMediaNote(ctx context.Context, id pgtype.UUID) (MediaNotes, error) {
	row := q.db.QueryRow(ctx, GetMediaNote, id)
	var i MediaNotes
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.Content,
		&i.Position,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PercentageLocation,
		&i.CharacterStart,
		&i.CharacterEnd,
		&i.EpubcfiLocation,
		&i.ChapterReference,
		&i.ParagraphReference,
		&i.DeviceSyncData,
	)
	return i, err
}

const GetMediaNotes = `-- name: GetMediaNotes :many
SELECT id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data FROM media_notes WHERE media_item_id = $1 AND user_id = $2 ORDER BY created_at DESC
`

type GetMediaNotesParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

func (q *Queries) GetMediaNotes(ctx context.Context, arg GetMediaNotesParams) ([]MediaNotes, error) {
	rows, err := q.db.Query(ctx, GetMediaNotes, arg.MediaItemID, arg.UserID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []MediaNotes{}
	for rows.Next() {
		var i MediaNotes
		if err := rows.Scan(
			&i.ID,
			&i.MediaItemID,
			&i.UserID,
			&i.Content,
			&i.Position,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.PercentageLocation,
			&i.CharacterStart,
			&i.CharacterEnd,
			&i.EpubcfiLocation,
			&i.ChapterReference,
			&i.ParagraphReference,
			&i.DeviceSyncData,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetMediaRating = `-- name: GetMediaRating :one
SELECT id, media_item_id, user_id, rating, created_at, updated_at FROM media_ratings WHERE media_item_id = $1 AND user_id = $2
`

type GetMediaRatingParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

func (q *Queries) GetMediaRating(ctx context.Context, arg GetMediaRatingParams) (MediaRatings, error) {
	row := q.db.QueryRow(ctx, GetMediaRating, arg.MediaItemID, arg.UserID)
	var i MediaRatings
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.Rating,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetMediaRatings = `-- name: GetMediaRatings :many
SELECT mr.id, mr.media_item_id, mr.user_id, mr.rating, mr.created_at, mr.updated_at, u.username
FROM media_ratings mr
JOIN users u ON mr.user_id = u.id
WHERE mr.media_item_id = $1
ORDER BY mr.created_at DESC
`

type GetMediaRatingsRow struct {
	ID          pgtype.UUID        `db:"id" json:"id"`
	MediaItemID pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID        `db:"user_id" json:"user_id"`
	Rating      int32              `db:"rating" json:"rating"`
	CreatedAt   pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt   pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	Username    string             `db:"username" json:"username"`
}

func (q *Queries) GetMediaRatings(ctx context.Context, mediaItemID pgtype.UUID) ([]GetMediaRatingsRow, error) {
	rows, err := q.db.Query(ctx, GetMediaRatings, mediaItemID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetMediaRatingsRow{}
	for rows.Next() {
		var i GetMediaRatingsRow
		if err := rows.Scan(
			&i.ID,
			&i.MediaItemID,
			&i.UserID,
			&i.Rating,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.Username,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetNextRetryTime = `-- name: GetNextRetryTime :one
SELECT
    CASE
        WHEN attempts = 0 THEN NOW()
        WHEN attempts = 1 THEN NOW() + INTERVAL '1 minute'
        WHEN attempts = 2 THEN NOW() + INTERVAL '5 minutes'
        WHEN attempts = 3 THEN NOW() + INTERVAL '15 minutes'
        WHEN attempts = 4 THEN NOW() + INTERVAL '1 hour'
        ELSE NOW() + INTERVAL '24 hours'
    END as next_retry_time
`

func (q *Queries) GetNextRetryTime(ctx context.Context) (interface{}, error) {
	row := q.db.QueryRow(ctx, GetNextRetryTime)
	var next_retry_time interface{}
	err := row.Scan(&next_retry_time)
	return next_retry_time, err
}

const GetNotStartedItems = `-- name: GetNotStartedItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE mi.library_id = $1
  AND NOT EXISTS (
    SELECT 1 FROM reading_progress rp
    WHERE rp.media_item_id = mi.id
      AND rp.user_id = $2
      AND rp.percentage > 0
  )
ORDER BY mi.created_at DESC
LIMIT $3
`

type GetNotStartedItemsParams struct {
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
	UserID    pgtype.UUID `db:"user_id" json:"user_id"`
	Limit     int32       `db:"limit" json:"limit"`
}

func (q *Queries) GetNotStartedItems(ctx context.Context, arg GetNotStartedItemsParams) ([]MediaItems, error) {
	rows, err := q.db.Query(ctx, GetNotStartedItems, arg.LibraryID, arg.UserID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []MediaItems{}
	for rows.Next() {
		var i MediaItems
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetOpdsToken = `-- name: GetOpdsToken :one
SELECT ot.id, ot.device_id, ot.token, ot.token_type, ot.expires_at, ot.created_at, d.device_name, d.device_type
FROM opds_tokens ot
JOIN devices d ON ot.device_id = d.id
WHERE ot.token = $1 AND ot.expires_at > NOW()
`

type GetOpdsTokenRow struct {
	ID         pgtype.UUID        `db:"id" json:"id"`
	DeviceID   pgtype.UUID        `db:"device_id" json:"device_id"`
	Token      string             `db:"token" json:"token"`
	TokenType  pgtype.Text        `db:"token_type" json:"token_type"`
	ExpiresAt  pgtype.Timestamptz `db:"expires_at" json:"expires_at"`
	CreatedAt  pgtype.Timestamptz `db:"created_at" json:"created_at"`
	DeviceName string             `db:"device_name" json:"device_name"`
	DeviceType string             `db:"device_type" json:"device_type"`
}

// Get OPDS token
func (q *Queries) GetOpdsToken(ctx context.Context, token string) (GetOpdsTokenRow, error) {
	row := q.db.QueryRow(ctx, GetOpdsToken, token)
	var i GetOpdsTokenRow
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.Token,
		&i.TokenType,
		&i.ExpiresAt,
		&i.CreatedAt,
		&i.DeviceName,
		&i.DeviceType,
	)
	return i, err
}

const GetOpdsTokensByDevice = `-- name: GetOpdsTokensByDevice :many
SELECT id, device_id, token, token_type, expires_at, created_at FROM opds_tokens WHERE device_id = $1 AND expires_at > NOW()
`

// Get OPDS tokens by device
func (q *Queries) GetOpdsTokensByDevice(ctx context.Context, deviceID pgtype.UUID) ([]OpdsTokens, error) {
	rows, err := q.db.Query(ctx, GetOpdsTokensByDevice, deviceID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []OpdsTokens{}
	for rows.Next() {
		var i OpdsTokens
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.Token,
			&i.TokenType,
			&i.ExpiresAt,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetPopularBooks = `-- name: GetPopularBooks :many
SELECT
    mi.id,
    mi.title,
    mi.author,
    COUNT(*) as read_count,
    AVG(rh.progress_percentage) as avg_completion,
     MAX(rh.created_at) as last_read
 FROM media_items mi
 JOIN reading_history rh ON rh.media_item_id = mi.id
 WHERE rh.user_id = $1
 GROUP BY mi.id, mi.title, mi.author
 ORDER BY read_count DESC
 LIMIT $2
`

type GetPopularBooksParams struct {
	UserID pgtype.UUID `db:"user_id" json:"user_id"`
	Limit  int32       `db:"limit" json:"limit"`
}

type GetPopularBooksRow struct {
	ID            pgtype.UUID `db:"id" json:"id"`
	Title         string      `db:"title" json:"title"`
	Author        pgtype.Text `db:"author" json:"author"`
	ReadCount     int64       `db:"read_count" json:"read_count"`
	AvgCompletion float64     `db:"avg_completion" json:"avg_completion"`
	LastRead      interface{} `db:"last_read" json:"last_read"`
}

// Get most popular books for a user
func (q *Queries) GetPopularBooks(ctx context.Context, arg GetPopularBooksParams) ([]GetPopularBooksRow, error) {
	rows, err := q.db.Query(ctx, GetPopularBooks, arg.UserID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetPopularBooksRow{}
	for rows.Next() {
		var i GetPopularBooksRow
		if err := rows.Scan(
			&i.ID,
			&i.Title,
			&i.Author,
			&i.ReadCount,
			&i.AvgCompletion,
			&i.LastRead,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetReadingHistory = `-- name: GetReadingHistory :many
SELECT id, user_id, media_item_id, device_id, progress_percentage, reading_session_start, reading_session_end, pages_read, time_spent_seconds, device_metadata, created_at
FROM reading_history
WHERE user_id = $1 AND media_item_id = $2
ORDER BY created_at DESC
LIMIT $3
`

type GetReadingHistoryParams struct {
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	Limit       int32       `db:"limit" json:"limit"`
}

// Get reading history for a user and book
func (q *Queries) GetReadingHistory(ctx context.Context, arg GetReadingHistoryParams) ([]ReadingHistory, error) {
	rows, err := q.db.Query(ctx, GetReadingHistory, arg.UserID, arg.MediaItemID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ReadingHistory{}
	for rows.Next() {
		var i ReadingHistory
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.MediaItemID,
			&i.DeviceID,
			&i.ProgressPercentage,
			&i.ReadingSessionStart,
			&i.ReadingSessionEnd,
			&i.PagesRead,
			&i.TimeSpentSeconds,
			&i.DeviceMetadata,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetReadingProgress = `-- name: GetReadingProgress :one
SELECT id, media_item_id, user_id, current_page, total_pages, last_read_at, percentage, character_offset, epubcfi, chapter, chapter_progress, viewport_x, viewport_y, zoom_level, scroll_position_x, scroll_position_y, panel_number, reading_mode, last_sync_device, last_sync_source, last_sync_timestamp, conflict_detected, conflict_resolved FROM reading_progress WHERE media_item_id = $1 AND user_id = $2
`

type GetReadingProgressParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

func (q *Queries) GetReadingProgress(ctx context.Context, arg GetReadingProgressParams) (ReadingProgress, error) {
	row := q.db.QueryRow(ctx, GetReadingProgress, arg.MediaItemID, arg.UserID)
	var i ReadingProgress
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.CurrentPage,
		&i.TotalPages,
		&i.LastReadAt,
		&i.Percentage,
		&i.CharacterOffset,
		&i.Epubcfi,
		&i.Chapter,
		&i.ChapterProgress,
		&i.ViewportX,
		&i.ViewportY,
		&i.ZoomLevel,
		&i.ScrollPositionX,
		&i.ScrollPositionY,
		&i.PanelNumber,
		&i.ReadingMode,
		&i.LastSyncDevice,
		&i.LastSyncSource,
		&i.LastSyncTimestamp,
		&i.ConflictDetected,
		&i.ConflictResolved,
	)
	return i, err
}

const GetRecentlyAddedItems = `-- name: GetRecentlyAddedItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
WHERE mi.library_id = $1
ORDER BY mi.created_at DESC
LIMIT $2
`

type GetRecentlyAddedItemsParams struct {
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
	Limit     int32       `db:"limit" json:"limit"`
}

func (q *Queries) GetRecentlyAddedItems(ctx context.Context, arg GetRecentlyAddedItemsParams) ([]MediaItems, error) {
	rows, err := q.db.Query(ctx, GetRecentlyAddedItems, arg.LibraryID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []MediaItems{}
	for rows.Next() {
		var i MediaItems
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetRecentlyReadItems = `-- name: GetRecentlyReadItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence FROM media_items mi
INNER JOIN (
    SELECT DISTINCT ON (media_item_id) media_item_id, last_read_at
    FROM reading_progress
    WHERE user_id = $2
      AND percentage >= 1
    ORDER BY media_item_id, last_read_at DESC
) rp ON rp.media_item_id = mi.id
WHERE mi.library_id = $1
ORDER BY rp.last_read_at DESC
LIMIT $3
`

type GetRecentlyReadItemsParams struct {
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
	UserID    pgtype.UUID `db:"user_id" json:"user_id"`
	Limit     int32       `db:"limit" json:"limit"`
}

func (q *Queries) GetRecentlyReadItems(ctx context.Context, arg GetRecentlyReadItemsParams) ([]MediaItems, error) {
	rows, err := q.db.Query(ctx, GetRecentlyReadItems, arg.LibraryID, arg.UserID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []MediaItems{}
	for rows.Next() {
		var i MediaItems
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetRefreshToken = `-- name: GetRefreshToken :one
SELECT rt.id, rt.user_id, rt.token, rt.expires_at, rt.created_at, rt.revoked_at, u.email, u.username, u.role
FROM refresh_tokens rt
JOIN users u ON rt.user_id = u.id
WHERE rt.token = $1 AND rt.revoked_at IS NULL AND rt.expires_at > NOW()
`

type GetRefreshTokenRow struct {
	ID        pgtype.UUID        `db:"id" json:"id"`
	UserID    pgtype.UUID        `db:"user_id" json:"user_id"`
	Token     pgtype.UUID        `db:"token" json:"token"`
	ExpiresAt pgtype.Timestamptz `db:"expires_at" json:"expires_at"`
	CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
	RevokedAt pgtype.Timestamptz `db:"revoked_at" json:"revoked_at"`
	Email     string             `db:"email" json:"email"`
	Username  string             `db:"username" json:"username"`
	Role      string             `db:"role" json:"role"`
}

func (q *Queries) GetRefreshToken(ctx context.Context, token pgtype.UUID) (GetRefreshTokenRow, error) {
	row := q.db.QueryRow(ctx, GetRefreshToken, token)
	var i GetRefreshTokenRow
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.Token,
		&i.ExpiresAt,
		&i.CreatedAt,
		&i.RevokedAt,
		&i.Email,
		&i.Username,
		&i.Role,
	)
	return i, err
}

const GetStuckSyncQueueItems = `-- name: GetStuckSyncQueueItems :many
SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue
WHERE status = 'processing' AND created_at < NOW() - INTERVAL '1 hour'
ORDER BY priority ASC, created_at ASC
`

func (q *Queries) GetStuckSyncQueueItems(ctx context.Context) ([]SyncQueue, error) {
	rows, err := q.db.Query(ctx, GetStuckSyncQueueItems)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []SyncQueue{}
	for rows.Next() {
		var i SyncQueue
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.SyncType,
			&i.SyncData,
			&i.Priority,
			&i.Attempts,
			&i.MaxAttempts,
			&i.Status,
			&i.ErrorMessage,
			&i.CreatedAt,
			&i.ProcessedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetSyncConflict = `-- name: GetSyncConflict :one
SELECT id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at FROM sync_conflicts WHERE id = $1
`

func (q *Queries) GetSyncConflict(ctx context.Context, id pgtype.UUID) (SyncConflicts, error) {
	row := q.db.QueryRow(ctx, GetSyncConflict, id)
	var i SyncConflicts
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.ConflictType,
		&i.ConflictData,
		&i.ResolutionStatus,
		&i.ResolutionData,
		&i.ResolvedBy,
		&i.ResolvedAt,
		&i.CreatedAt,
	)
	return i, err
}

const GetSyncQueueItem = `-- name: GetSyncQueueItem :one
SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue WHERE id = $1
`

func (q *Queries) GetSyncQueueItem(ctx context.Context, id pgtype.UUID) (SyncQueue, error) {
	row := q.db.QueryRow(ctx, GetSyncQueueItem, id)
	var i SyncQueue
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.SyncType,
		&i.SyncData,
		&i.Priority,
		&i.Attempts,
		&i.MaxAttempts,
		&i.Status,
		&i.ErrorMessage,
		&i.CreatedAt,
		&i.ProcessedAt,
	)
	return i, err
}

const GetSyncQueueStats = `-- name: GetSyncQueueStats :one
SELECT
    COUNT(*) FILTER (WHERE status = 'pending') as pending_count,
    COUNT(*) FILTER (WHERE status = 'processing') as processing_count,
    COUNT(*) FILTER (WHERE status = 'failed') as failed_count,
    COUNT(*) FILTER (WHERE status = 'completed') as completed_count,
    COUNT(*) as total_count
FROM sync_queue
WHERE device_id = $1
`

type GetSyncQueueStatsRow struct {
	PendingCount    int64 `db:"pending_count" json:"pending_count"`
	ProcessingCount int64 `db:"processing_count" json:"processing_count"`
	FailedCount     int64 `db:"failed_count" json:"failed_count"`
	CompletedCount  int64 `db:"completed_count" json:"completed_count"`
	TotalCount      int64 `db:"total_count" json:"total_count"`
}

func (q *Queries) GetSyncQueueStats(ctx context.Context, deviceID pgtype.UUID) (GetSyncQueueStatsRow, error) {
	row := q.db.QueryRow(ctx, GetSyncQueueStats, deviceID)
	var i GetSyncQueueStatsRow
	err := row.Scan(
		&i.PendingCount,
		&i.ProcessingCount,
		&i.FailedCount,
		&i.CompletedCount,
		&i.TotalCount,
	)
	return i, err
}

const GetSystemCollectionsForDashboard = `-- name: GetSystemCollectionsForDashboard :many
SELECT id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at FROM collections
WHERE user_id = $1
  AND is_system_collection = true
  AND show_on_dashboard = true
ORDER BY priority ASC
`

// Dashboard collections queries
func (q *Queries) GetSystemCollectionsForDashboard(ctx context.Context, userID pgtype.UUID) ([]Collections, error) {
	rows, err := q.db.Query(ctx, GetSystemCollectionsForDashboard, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []Collections{}
	for rows.Next() {
		var i Collections
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.Name,
			&i.Description,
			&i.Color,
			&i.Icon,
			&i.AutoAssignRules,
			&i.ViewSettings,
			&i.ShowOnDashboard,
			&i.QueryType,
			&i.Priority,
			&i.IsSystemCollection,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetSystemConfig = `-- name: GetSystemConfig :one

SELECT key, value, updated_at, updated_by FROM system_config WHERE key = $1
`

// SYSTEM CONFIG QUERIES
// Get system config
func (q *Queries) GetSystemConfig(ctx context.Context, key string) (SystemConfig, error) {
	row := q.db.QueryRow(ctx, GetSystemConfig, key)
	var i SystemConfig
	err := row.Scan(
		&i.Key,
		&i.Value,
		&i.UpdatedAt,
		&i.UpdatedBy,
	)
	return i, err
}

const GetSystemSetting = `-- name: GetSystemSetting :one
SELECT setting_value FROM system_settings WHERE setting_key = $1
`

// System Settings queries
func (q *Queries) GetSystemSetting(ctx context.Context, settingKey string) (string, error) {
	row := q.db.QueryRow(ctx, GetSystemSetting, settingKey)
	var setting_value string
	err := row.Scan(&setting_value)
	return setting_value, err
}

const GetUniversalProgress = `-- name: GetUniversalProgress :one
SELECT
    rp.id,
    rp.media_item_id,
    rp.user_id,
    rp.current_page,
    rp.total_pages,
    rp.last_read_at,
    rp.percentage,
    rp.character_offset,
    rp.epubcfi,
    rp.chapter,
    rp.chapter_progress,
    rp.viewport_x,
    rp.viewport_y,
    rp.zoom_level,
    rp.scroll_position_x,
    rp.scroll_position_y,
    rp.panel_number,
    rp.reading_mode,
    rp.last_sync_device,
    rp.last_sync_source,
    rp.last_sync_timestamp,
    rp.conflict_detected,
    rp.conflict_resolved,
    mi.format_group,
    mi.format_mimetype,
    mi.is_reflowable,
    mi.has_fixed_layout,
    mi.total_characters,
    mi.chapter_count
FROM reading_progress rp
JOIN media_items mi ON rp.media_item_id = mi.id
WHERE rp.media_item_id = $1 AND rp.user_id = $2
`

type GetUniversalProgressParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

type GetUniversalProgressRow struct {
	ID                pgtype.UUID        `db:"id" json:"id"`
	MediaItemID       pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	UserID            pgtype.UUID        `db:"user_id" json:"user_id"`
	CurrentPage       pgtype.Int4        `db:"current_page" json:"current_page"`
	TotalPages        pgtype.Int4        `db:"total_pages" json:"total_pages"`
	LastReadAt        pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
	Percentage        pgtype.Float8      `db:"percentage" json:"percentage"`
	CharacterOffset   pgtype.Int8        `db:"character_offset" json:"character_offset"`
	Epubcfi           pgtype.Text        `db:"epubcfi" json:"epubcfi"`
	Chapter           pgtype.Int4        `db:"chapter" json:"chapter"`
	ChapterProgress   pgtype.Float8      `db:"chapter_progress" json:"chapter_progress"`
	ViewportX         pgtype.Float8      `db:"viewport_x" json:"viewport_x"`
	ViewportY         pgtype.Float8      `db:"viewport_y" json:"viewport_y"`
	ZoomLevel         pgtype.Float8      `db:"zoom_level" json:"zoom_level"`
	ScrollPositionX   pgtype.Float8      `db:"scroll_position_x" json:"scroll_position_x"`
	ScrollPositionY   pgtype.Float8      `db:"scroll_position_y" json:"scroll_position_y"`
	PanelNumber       pgtype.Int4        `db:"panel_number" json:"panel_number"`
	ReadingMode       pgtype.Text        `db:"reading_mode" json:"reading_mode"`
	LastSyncDevice    pgtype.Text        `db:"last_sync_device" json:"last_sync_device"`
	LastSyncSource    pgtype.Text        `db:"last_sync_source" json:"last_sync_source"`
	LastSyncTimestamp pgtype.Timestamptz `db:"last_sync_timestamp" json:"last_sync_timestamp"`
	ConflictDetected  pgtype.Bool        `db:"conflict_detected" json:"conflict_detected"`
	ConflictResolved  pgtype.Bool        `db:"conflict_resolved" json:"conflict_resolved"`
	FormatGroup       string             `db:"format_group" json:"format_group"`
	FormatMimetype    pgtype.Text        `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable      pgtype.Bool        `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout    pgtype.Bool        `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters   pgtype.Int8        `db:"total_characters" json:"total_characters"`
	ChapterCount      pgtype.Int4        `db:"chapter_count" json:"chapter_count"`
}

// Get universal progress for a book
func (q *Queries) GetUniversalProgress(ctx context.Context, arg GetUniversalProgressParams) (GetUniversalProgressRow, error) {
	row := q.db.QueryRow(ctx, GetUniversalProgress, arg.MediaItemID, arg.UserID)
	var i GetUniversalProgressRow
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.CurrentPage,
		&i.TotalPages,
		&i.LastReadAt,
		&i.Percentage,
		&i.CharacterOffset,
		&i.Epubcfi,
		&i.Chapter,
		&i.ChapterProgress,
		&i.ViewportX,
		&i.ViewportY,
		&i.ZoomLevel,
		&i.ScrollPositionX,
		&i.ScrollPositionY,
		&i.PanelNumber,
		&i.ReadingMode,
		&i.LastSyncDevice,
		&i.LastSyncSource,
		&i.LastSyncTimestamp,
		&i.ConflictDetected,
		&i.ConflictResolved,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
	)
	return i, err
}

const GetUnlinkedBookByContentId = `-- name: GetUnlinkedBookByContentId :one
SELECT id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at FROM unlinked_books WHERE device_id = $1 AND content_id = $2
`

type GetUnlinkedBookByContentIdParams struct {
	DeviceID  pgtype.UUID `db:"device_id" json:"device_id"`
	ContentID string      `db:"content_id" json:"content_id"`
}

// Get unlinked book by ContentId
func (q *Queries) GetUnlinkedBookByContentId(ctx context.Context, arg GetUnlinkedBookByContentIdParams) (UnlinkedBooks, error) {
	row := q.db.QueryRow(ctx, GetUnlinkedBookByContentId, arg.DeviceID, arg.ContentID)
	var i UnlinkedBooks
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.ContentID,
		&i.FilePath,
		&i.Title,
		&i.Author,
		&i.ConfidenceScore,
		&i.Resolved,
		&i.MediaItemID,
		&i.ResolvedAt,
		&i.ResolutionMethod,
		&i.LastSeenAt,
		&i.CreatedAt,
	)
	return i, err
}

const GetUnlinkedBookByID = `-- name: GetUnlinkedBookByID :one
SELECT id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at FROM unlinked_books WHERE id = $1
`

// Get unlinked book by ID
func (q *Queries) GetUnlinkedBookByID(ctx context.Context, id pgtype.UUID) (UnlinkedBooks, error) {
	row := q.db.QueryRow(ctx, GetUnlinkedBookByID, id)
	var i UnlinkedBooks
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.ContentID,
		&i.FilePath,
		&i.Title,
		&i.Author,
		&i.ConfidenceScore,
		&i.Resolved,
		&i.MediaItemID,
		&i.ResolvedAt,
		&i.ResolutionMethod,
		&i.LastSeenAt,
		&i.CreatedAt,
	)
	return i, err
}

const GetUnlinkedBooksByDevice = `-- name: GetUnlinkedBooksByDevice :many
SELECT ub.id, ub.device_id, ub.content_id, ub.file_path, ub.title, ub.author, ub.confidence_score, ub.resolved, ub.media_item_id, ub.resolved_at, ub.resolution_method, ub.last_seen_at, ub.created_at, d.device_name, d.device_type
FROM unlinked_books ub
JOIN devices d ON ub.device_id = d.id
WHERE ub.device_id = $1 AND ub.resolved = false
ORDER BY ub.last_seen_at DESC
`

type GetUnlinkedBooksByDeviceRow struct {
	ID               pgtype.UUID        `db:"id" json:"id"`
	DeviceID         pgtype.UUID        `db:"device_id" json:"device_id"`
	ContentID        string             `db:"content_id" json:"content_id"`
	FilePath         pgtype.Text        `db:"file_path" json:"file_path"`
	Title            pgtype.Text        `db:"title" json:"title"`
	Author           pgtype.Text        `db:"author" json:"author"`
	ConfidenceScore  pgtype.Float8      `db:"confidence_score" json:"confidence_score"`
	Resolved         pgtype.Bool        `db:"resolved" json:"resolved"`
	MediaItemID      pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	ResolvedAt       pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
	ResolutionMethod pgtype.Text        `db:"resolution_method" json:"resolution_method"`
	LastSeenAt       pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"`
	CreatedAt        pgtype.Timestamptz `db:"created_at" json:"created_at"`
	DeviceName       string             `db:"device_name" json:"device_name"`
	DeviceType       string             `db:"device_type" json:"device_type"`
}

// Get unlinked books for a device
func (q *Queries) GetUnlinkedBooksByDevice(ctx context.Context, deviceID pgtype.UUID) ([]GetUnlinkedBooksByDeviceRow, error) {
	rows, err := q.db.Query(ctx, GetUnlinkedBooksByDevice, deviceID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetUnlinkedBooksByDeviceRow{}
	for rows.Next() {
		var i GetUnlinkedBooksByDeviceRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.ContentID,
			&i.FilePath,
			&i.Title,
			&i.Author,
			&i.ConfidenceScore,
			&i.Resolved,
			&i.MediaItemID,
			&i.ResolvedAt,
			&i.ResolutionMethod,
			&i.LastSeenAt,
			&i.CreatedAt,
			&i.DeviceName,
			&i.DeviceType,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetUser = `-- name: GetUser :one
SELECT
    u.id,
    u.email,
    u.username,
    u.theme,
    u.first_name,
    u.last_name,
    u.role,
    u.max_devices,
    u.created_at,
    u.updated_at,
    (SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count
FROM users u
WHERE u.id = $1
`

type GetUserRow struct {
	ID          pgtype.UUID        `db:"id" json:"id"`
	Email       string             `db:"email" json:"email"`
	Username    string             `db:"username" json:"username"`
	Theme       pgtype.Text        `db:"theme" json:"theme"`
	FirstName   pgtype.Text        `db:"first_name" json:"first_name"`
	LastName    pgtype.Text        `db:"last_name" json:"last_name"`
	Role        string             `db:"role" json:"role"`
	MaxDevices  pgtype.Int4        `db:"max_devices" json:"max_devices"`
	CreatedAt   pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt   pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	DeviceCount int64              `db:"device_count" json:"device_count"`
}

func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, error) {
	row := q.db.QueryRow(ctx, GetUser, id)
	var i GetUserRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.Username,
		&i.Theme,
		&i.FirstName,
		&i.LastName,
		&i.Role,
		&i.MaxDevices,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DeviceCount,
	)
	return i, err
}

const GetUserByEmail = `-- name: GetUserByEmail :one
SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1
`

type GetUserByEmailRow struct {
	ID        pgtype.UUID        `db:"id" json:"id"`
	Email     string             `db:"email" json:"email"`
	Username  string             `db:"username" json:"username"`
	Theme     pgtype.Text        `db:"theme" json:"theme"`
	FirstName pgtype.Text        `db:"first_name" json:"first_name"`
	LastName  pgtype.Text        `db:"last_name" json:"last_name"`
	Role      string             `db:"role" json:"role"`
	CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}

func (q *Queries) GetUserByEmail(ctx context.Context, email string) (GetUserByEmailRow, error) {
	row := q.db.QueryRow(ctx, GetUserByEmail, email)
	var i GetUserByEmailRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.Username,
		&i.Theme,
		&i.FirstName,
		&i.LastName,
		&i.Role,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one
SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1
`

type GetUserByEmailOrUsernameRow struct {
	ID        pgtype.UUID        `db:"id" json:"id"`
	Email     string             `db:"email" json:"email"`
	Username  string             `db:"username" json:"username"`
	Theme     pgtype.Text        `db:"theme" json:"theme"`
	FirstName pgtype.Text        `db:"first_name" json:"first_name"`
	LastName  pgtype.Text        `db:"last_name" json:"last_name"`
	Role      string             `db:"role" json:"role"`
	CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}

func (q *Queries) GetUserByEmailOrUsername(ctx context.Context, email string) (GetUserByEmailOrUsernameRow, error) {
	row := q.db.QueryRow(ctx, GetUserByEmailOrUsername, email)
	var i GetUserByEmailOrUsernameRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.Username,
		&i.Theme,
		&i.FirstName,
		&i.LastName,
		&i.Role,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetUserByUsername = `-- name: GetUserByUsername :one
SELECT id, email, username, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE username = $1
`

type GetUserByUsernameRow struct {
	ID        pgtype.UUID        `db:"id" json:"id"`
	Email     string             `db:"email" json:"email"`
	Username  string             `db:"username" json:"username"`
	Theme     pgtype.Text        `db:"theme" json:"theme"`
	FirstName pgtype.Text        `db:"first_name" json:"first_name"`
	LastName  pgtype.Text        `db:"last_name" json:"last_name"`
	Role      string             `db:"role" json:"role"`
	CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}

func (q *Queries) GetUserByUsername(ctx context.Context, username string) (GetUserByUsernameRow, error) {
	row := q.db.QueryRow(ctx, GetUserByUsername, username)
	var i GetUserByUsernameRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.Username,
		&i.Theme,
		&i.FirstName,
		&i.LastName,
		&i.Role,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetUserCollectionsForDashboard = `-- name: GetUserCollectionsForDashboard :many
SELECT c.id, c.user_id, c.name, c.description, c.color, c.icon, c.auto_assign_rules, c.view_settings, c.show_on_dashboard, c.query_type, c.priority, c.is_system_collection, c.created_at FROM collections c
WHERE c.user_id = $1
  AND c.show_on_dashboard = true
  AND c.is_system_collection = false
ORDER BY priority ASC
`

func (q *Queries) GetUserCollectionsForDashboard(ctx context.Context, userID pgtype.UUID) ([]Collections, error) {
	rows, err := q.db.Query(ctx, GetUserCollectionsForDashboard, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []Collections{}
	for rows.Next() {
		var i Collections
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.Name,
			&i.Description,
			&i.Color,
			&i.Icon,
			&i.AutoAssignRules,
			&i.ViewSettings,
			&i.ShowOnDashboard,
			&i.QueryType,
			&i.Priority,
			&i.IsSystemCollection,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetUserDeviceUsage = `-- name: GetUserDeviceUsage :many
SELECT
    d.id,
    d.device_name,
    d.device_type,
    COUNT(*) as sync_count,
    MAX(rh.created_at) as last_sync,
    SUM(rh.time_spent_seconds) as total_time_seconds
FROM devices d
JOIN reading_history rh ON rh.device_id = d.id
WHERE d.user_id = $1
GROUP BY d.id, d.device_name, d.device_type
ORDER BY sync_count DESC
`

type GetUserDeviceUsageRow struct {
	ID               pgtype.UUID `db:"id" json:"id"`
	DeviceName       string      `db:"device_name" json:"device_name"`
	DeviceType       string      `db:"device_type" json:"device_type"`
	SyncCount        int64       `db:"sync_count" json:"sync_count"`
	LastSync         interface{} `db:"last_sync" json:"last_sync"`
	TotalTimeSeconds int64       `db:"total_time_seconds" json:"total_time_seconds"`
}

// Get user device usage statistics
func (q *Queries) GetUserDeviceUsage(ctx context.Context, userID pgtype.UUID) ([]GetUserDeviceUsageRow, error) {
	rows, err := q.db.Query(ctx, GetUserDeviceUsage, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetUserDeviceUsageRow{}
	for rows.Next() {
		var i GetUserDeviceUsageRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceName,
			&i.DeviceType,
			&i.SyncCount,
			&i.LastSync,
			&i.TotalTimeSeconds,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetUserForLogin = `-- name: GetUserForLogin :one
SELECT id, email, username, password_hash, theme, first_name, last_name, role, created_at, updated_at FROM users WHERE email = $1 OR username = $1
`

type GetUserForLoginRow struct {
	ID           pgtype.UUID        `db:"id" json:"id"`
	Email        string             `db:"email" json:"email"`
	Username     string             `db:"username" json:"username"`
	PasswordHash string             `db:"password_hash" json:"password_hash"`
	Theme        pgtype.Text        `db:"theme" json:"theme"`
	FirstName    pgtype.Text        `db:"first_name" json:"first_name"`
	LastName     pgtype.Text        `db:"last_name" json:"last_name"`
	Role         string             `db:"role" json:"role"`
	CreatedAt    pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt    pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
}

func (q *Queries) GetUserForLogin(ctx context.Context, email string) (GetUserForLoginRow, error) {
	row := q.db.QueryRow(ctx, GetUserForLogin, email)
	var i GetUserForLoginRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.Username,
		&i.PasswordHash,
		&i.Theme,
		&i.FirstName,
		&i.LastName,
		&i.Role,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const GetUserMediaItemsForSync = `-- name: GetUserMediaItemsForSync :many
SELECT
    mi.id,
    mi.title,
    mi.author,
    mi.file_path,
    mi.mime_type,
    mi.page_count,
    mi.format_group,
    mi.total_characters,
    mi.chapter_count,
    mi.entitlement_id,
    mi.revision_number,
    mi.file_size,
    mi.file_sha256
FROM media_items mi
JOIN library_visibility lv ON mi.library_id = lv.library_id
WHERE lv.user_id = $1
  AND lv.is_visible = true
ORDER BY mi.title ASC
LIMIT 1000
`

type GetUserMediaItemsForSyncRow struct {
	ID              pgtype.UUID `db:"id" json:"id"`
	Title           string      `db:"title" json:"title"`
	Author          pgtype.Text `db:"author" json:"author"`
	FilePath        string      `db:"file_path" json:"file_path"`
	MimeType        pgtype.Text `db:"mime_type" json:"mime_type"`
	PageCount       pgtype.Int4 `db:"page_count" json:"page_count"`
	FormatGroup     string      `db:"format_group" json:"format_group"`
	TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
	ChapterCount    pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
	EntitlementID   pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber  pgtype.Int4 `db:"revision_number" json:"revision_number"`
	FileSize        pgtype.Int8 `db:"file_size" json:"file_size"`
	FileSha256      pgtype.Text `db:"file_sha256" json:"file_sha256"`
}

func (q *Queries) GetUserMediaItemsForSync(ctx context.Context, userID pgtype.UUID) ([]GetUserMediaItemsForSyncRow, error) {
	rows, err := q.db.Query(ctx, GetUserMediaItemsForSync, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetUserMediaItemsForSyncRow{}
	for rows.Next() {
		var i GetUserMediaItemsForSyncRow
		if err := rows.Scan(
			&i.ID,
			&i.Title,
			&i.Author,
			&i.FilePath,
			&i.MimeType,
			&i.PageCount,
			&i.FormatGroup,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.FileSize,
			&i.FileSha256,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetUserPasswordHash = `-- name: GetUserPasswordHash :one
SELECT password_hash FROM users WHERE id = $1
`

func (q *Queries) GetUserPasswordHash(ctx context.Context, id pgtype.UUID) (string, error) {
	row := q.db.QueryRow(ctx, GetUserPasswordHash, id)
	var password_hash string
	err := row.Scan(&password_hash)
	return password_hash, err
}

const GetUserProgressForBooks = `-- name: GetUserProgressForBooks :many
SELECT
    rp.media_item_id,
    rp.user_id,
    rp.percentage,
    rp.character_offset,
    rp.epubcfi,
    rp.chapter,
    rp.chapter_progress,
    rp.current_page,
    rp.total_pages,
    rp.last_read_at,
    rp.last_sync_device,
    rp.last_sync_source,
    mi.title,
    mi.author,
    mi.file_path
FROM reading_progress rp
JOIN media_items mi ON rp.media_item_id = mi.id
WHERE rp.user_id = $1
  AND rp.media_item_id = ANY($2::uuid[])
ORDER BY rp.last_read_at DESC
`

type GetUserProgressForBooksParams struct {
	UserID  pgtype.UUID   `db:"user_id" json:"user_id"`
	Column2 []pgtype.UUID `db:"column_2" json:"column_2"`
}

type GetUserProgressForBooksRow struct {
	MediaItemID     pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	UserID          pgtype.UUID        `db:"user_id" json:"user_id"`
	Percentage      pgtype.Float8      `db:"percentage" json:"percentage"`
	CharacterOffset pgtype.Int8        `db:"character_offset" json:"character_offset"`
	Epubcfi         pgtype.Text        `db:"epubcfi" json:"epubcfi"`
	Chapter         pgtype.Int4        `db:"chapter" json:"chapter"`
	ChapterProgress pgtype.Float8      `db:"chapter_progress" json:"chapter_progress"`
	CurrentPage     pgtype.Int4        `db:"current_page" json:"current_page"`
	TotalPages      pgtype.Int4        `db:"total_pages" json:"total_pages"`
	LastReadAt      pgtype.Timestamptz `db:"last_read_at" json:"last_read_at"`
	LastSyncDevice  pgtype.Text        `db:"last_sync_device" json:"last_sync_device"`
	LastSyncSource  pgtype.Text        `db:"last_sync_source" json:"last_sync_source"`
	Title           string             `db:"title" json:"title"`
	Author          pgtype.Text        `db:"author" json:"author"`
	FilePath        string             `db:"file_path" json:"file_path"`
}

func (q *Queries) GetUserProgressForBooks(ctx context.Context, arg GetUserProgressForBooksParams) ([]GetUserProgressForBooksRow, error) {
	rows, err := q.db.Query(ctx, GetUserProgressForBooks, arg.UserID, arg.Column2)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetUserProgressForBooksRow{}
	for rows.Next() {
		var i GetUserProgressForBooksRow
		if err := rows.Scan(
			&i.MediaItemID,
			&i.UserID,
			&i.Percentage,
			&i.CharacterOffset,
			&i.Epubcfi,
			&i.Chapter,
			&i.ChapterProgress,
			&i.CurrentPage,
			&i.TotalPages,
			&i.LastReadAt,
			&i.LastSyncDevice,
			&i.LastSyncSource,
			&i.Title,
			&i.Author,
			&i.FilePath,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetUserReadingHistory = `-- name: GetUserReadingHistory :many

SELECT
    rh.id,
    rh.user_id,
    rh.media_item_id,
    rh.device_id,
    rh.progress_percentage,
    rh.reading_session_start,
    rh.reading_session_end,
    rh.pages_read,
    rh.time_spent_seconds,
    rh.device_metadata,
    rh.created_at,
    mi.title,
    mi.author,
    d.device_name,
    d.device_type
FROM reading_history rh
JOIN media_items mi ON rh.media_item_id = mi.id
LEFT JOIN devices d ON rh.device_id = d.id
WHERE rh.user_id = $1
  AND rh.created_at >= $2
  AND rh.created_at <= $3
ORDER BY rh.created_at DESC
`

type GetUserReadingHistoryParams struct {
	UserID      pgtype.UUID        `db:"user_id" json:"user_id"`
	CreatedAt   pgtype.Timestamptz `db:"created_at" json:"created_at"`
	CreatedAt_2 pgtype.Timestamptz `db:"created_at_2" json:"created_at_2"`
}

type GetUserReadingHistoryRow struct {
	ID                  pgtype.UUID        `db:"id" json:"id"`
	UserID              pgtype.UUID        `db:"user_id" json:"user_id"`
	MediaItemID         pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	DeviceID            pgtype.UUID        `db:"device_id" json:"device_id"`
	ProgressPercentage  pgtype.Float8      `db:"progress_percentage" json:"progress_percentage"`
	ReadingSessionStart pgtype.Timestamptz `db:"reading_session_start" json:"reading_session_start"`
	ReadingSessionEnd   pgtype.Timestamptz `db:"reading_session_end" json:"reading_session_end"`
	PagesRead           pgtype.Int4        `db:"pages_read" json:"pages_read"`
	TimeSpentSeconds    pgtype.Int4        `db:"time_spent_seconds" json:"time_spent_seconds"`
	DeviceMetadata      []byte             `db:"device_metadata" json:"device_metadata"`
	CreatedAt           pgtype.Timestamptz `db:"created_at" json:"created_at"`
	Title               string             `db:"title" json:"title"`
	Author              pgtype.Text        `db:"author" json:"author"`
	DeviceName          pgtype.Text        `db:"device_name" json:"device_name"`
	DeviceType          pgtype.Text        `db:"device_type" json:"device_type"`
}

// Analytics queries
// Get user reading history for analytics
func (q *Queries) GetUserReadingHistory(ctx context.Context, arg GetUserReadingHistoryParams) ([]GetUserReadingHistoryRow, error) {
	rows, err := q.db.Query(ctx, GetUserReadingHistory, arg.UserID, arg.CreatedAt, arg.CreatedAt_2)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetUserReadingHistoryRow{}
	for rows.Next() {
		var i GetUserReadingHistoryRow
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.MediaItemID,
			&i.DeviceID,
			&i.ProgressPercentage,
			&i.ReadingSessionStart,
			&i.ReadingSessionEnd,
			&i.PagesRead,
			&i.TimeSpentSeconds,
			&i.DeviceMetadata,
			&i.CreatedAt,
			&i.Title,
			&i.Author,
			&i.DeviceName,
			&i.DeviceType,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const GetUserVisibleLibraries = `-- name: GetUserVisibleLibraries :many
SELECT l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at, lt.name as type_name, lt.description as type_description,
       COALESCE(lv.is_visible, true) as is_visible
FROM libraries l
JOIN library_types lt ON l.library_type_id = lt.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
WHERE COALESCE(lv.is_visible, true) = true
ORDER BY l.created_at ASC
`

type GetUserVisibleLibrariesRow struct {
	ID               pgtype.UUID        `db:"id" json:"id"`
	Name             string             `db:"name" json:"name"`
	Description      pgtype.Text        `db:"description" json:"description"`
	LibraryTypeID    pgtype.UUID        `db:"library_type_id" json:"library_type_id"`
	CreatedByAdminID pgtype.UUID        `db:"created_by_admin_id" json:"created_by_admin_id"`
	CreatedAt        pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	TypeName         string             `db:"type_name" json:"type_name"`
	TypeDescription  pgtype.Text        `db:"type_description" json:"type_description"`
	IsVisible        bool               `db:"is_visible" json:"is_visible"`
}

func (q *Queries) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUID) ([]GetUserVisibleLibrariesRow, error) {
	rows, err := q.db.Query(ctx, GetUserVisibleLibraries, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []GetUserVisibleLibrariesRow{}
	for rows.Next() {
		var i GetUserVisibleLibrariesRow
		if err := rows.Scan(
			&i.ID,
			&i.Name,
			&i.Description,
			&i.LibraryTypeID,
			&i.CreatedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.TypeName,
			&i.TypeDescription,
			&i.IsVisible,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const IncrementSyncQueueAttempts = `-- name: IncrementSyncQueueAttempts :one
UPDATE sync_queue
SET
    attempts = attempts + 1,
    status = CASE
        WHEN attempts + 1 >= max_attempts THEN 'failed'
        ELSE 'pending'
    END,
    error_message = $2
WHERE id = $1
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`

type IncrementSyncQueueAttemptsParams struct {
	ID           pgtype.UUID `db:"id" json:"id"`
	ErrorMessage pgtype.Text `db:"error_message" json:"error_message"`
}

func (q *Queries) IncrementSyncQueueAttempts(ctx context.Context, arg IncrementSyncQueueAttemptsParams) (SyncQueue, error) {
	row := q.db.QueryRow(ctx, IncrementSyncQueueAttempts, arg.ID, arg.ErrorMessage)
	var i SyncQueue
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.SyncType,
		&i.SyncData,
		&i.Priority,
		&i.Attempts,
		&i.MaxAttempts,
		&i.Status,
		&i.ErrorMessage,
		&i.CreatedAt,
		&i.ProcessedAt,
	)
	return i, err
}

const IsBookInCollection = `-- name: IsBookInCollection :one
SELECT EXISTS(
    SELECT 1 FROM collection_items
    WHERE collection_id = $1 AND media_item_id = $2
) as in_collection
`

type IsBookInCollectionParams struct {
	CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
	MediaItemID  pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}

// Check if book is in collection
func (q *Queries) IsBookInCollection(ctx context.Context, arg IsBookInCollectionParams) (bool, error) {
	row := q.db.QueryRow(ctx, IsBookInCollection, arg.CollectionID, arg.MediaItemID)
	var in_collection bool
	err := row.Scan(&in_collection)
	return in_collection, err
}

const IsBookOnKoboShelf = `-- name: IsBookOnKoboShelf :one
SELECT EXISTS(
    SELECT 1 FROM kobo_shelves
    WHERE device_id = $1 AND media_item_id = $2
) as on_shelf
`

type IsBookOnKoboShelfParams struct {
	DeviceID    pgtype.UUID `db:"device_id" json:"device_id"`
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}

func (q *Queries) IsBookOnKoboShelf(ctx context.Context, arg IsBookOnKoboShelfParams) (bool, error) {
	row := q.db.QueryRow(ctx, IsBookOnKoboShelf, arg.DeviceID, arg.MediaItemID)
	var on_shelf bool
	err := row.Scan(&on_shelf)
	return on_shelf, err
}

const LinkUnlinkedBook = `-- name: LinkUnlinkedBook :one
UPDATE unlinked_books
SET
    media_item_id = $2,
    confidence_score = $3,
    resolved = true,
    resolved_at = NOW(),
    resolution_method = 'manual_link'
WHERE id = $1
RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at
`

type LinkUnlinkedBookParams struct {
	ID              pgtype.UUID   `db:"id" json:"id"`
	MediaItemID     pgtype.UUID   `db:"media_item_id" json:"media_item_id"`
	ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
}

// Link unlinked book to media item
func (q *Queries) LinkUnlinkedBook(ctx context.Context, arg LinkUnlinkedBookParams) (UnlinkedBooks, error) {
	row := q.db.QueryRow(ctx, LinkUnlinkedBook, arg.ID, arg.MediaItemID, arg.ConfidenceScore)
	var i UnlinkedBooks
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.ContentID,
		&i.FilePath,
		&i.Title,
		&i.Author,
		&i.ConfidenceScore,
		&i.Resolved,
		&i.MediaItemID,
		&i.ResolvedAt,
		&i.ResolutionMethod,
		&i.LastSeenAt,
		&i.CreatedAt,
	)
	return i, err
}

const ListAllSyncQueueItems = `-- name: ListAllSyncQueueItems :many
SELECT
    sq.id, sq.device_id, sq.media_item_id, sq.sync_type, sq.sync_data, sq.priority, sq.attempts, sq.max_attempts, sq.status, sq.error_message, sq.created_at, sq.processed_at,
    d.device_name,
    d.device_type,
    u.email as user_email,
    mi.title as media_title
FROM sync_queue sq
JOIN devices d ON sq.device_id = d.id
JOIN users u ON d.user_id = u.id
LEFT JOIN media_items mi ON sq.media_item_id = mi.id
ORDER BY sq.priority ASC, sq.created_at DESC
LIMIT $1 OFFSET $2
`

type ListAllSyncQueueItemsParams struct {
	Limit  int32 `db:"limit" json:"limit"`
	Offset int32 `db:"offset" json:"offset"`
}

type ListAllSyncQueueItemsRow struct {
	ID           pgtype.UUID        `db:"id" json:"id"`
	DeviceID     pgtype.UUID        `db:"device_id" json:"device_id"`
	MediaItemID  pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	SyncType     string             `db:"sync_type" json:"sync_type"`
	SyncData     []byte             `db:"sync_data" json:"sync_data"`
	Priority     pgtype.Int4        `db:"priority" json:"priority"`
	Attempts     pgtype.Int4        `db:"attempts" json:"attempts"`
	MaxAttempts  pgtype.Int4        `db:"max_attempts" json:"max_attempts"`
	Status       pgtype.Text        `db:"status" json:"status"`
	ErrorMessage pgtype.Text        `db:"error_message" json:"error_message"`
	CreatedAt    pgtype.Timestamptz `db:"created_at" json:"created_at"`
	ProcessedAt  pgtype.Timestamptz `db:"processed_at" json:"processed_at"`
	DeviceName   string             `db:"device_name" json:"device_name"`
	DeviceType   string             `db:"device_type" json:"device_type"`
	UserEmail    string             `db:"user_email" json:"user_email"`
	MediaTitle   pgtype.Text        `db:"media_title" json:"media_title"`
}

func (q *Queries) ListAllSyncQueueItems(ctx context.Context, arg ListAllSyncQueueItemsParams) ([]ListAllSyncQueueItemsRow, error) {
	rows, err := q.db.Query(ctx, ListAllSyncQueueItems, arg.Limit, arg.Offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListAllSyncQueueItemsRow{}
	for rows.Next() {
		var i ListAllSyncQueueItemsRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.SyncType,
			&i.SyncData,
			&i.Priority,
			&i.Attempts,
			&i.MaxAttempts,
			&i.Status,
			&i.ErrorMessage,
			&i.CreatedAt,
			&i.ProcessedAt,
			&i.DeviceName,
			&i.DeviceType,
			&i.UserEmail,
			&i.MediaTitle,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListDevicesByType = `-- name: ListDevicesByType :many
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE device_type = $1 ORDER BY created_at DESC
`

func (q *Queries) ListDevicesByType(ctx context.Context, deviceType string) ([]Devices, error) {
	rows, err := q.db.Query(ctx, ListDevicesByType, deviceType)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []Devices{}
	for rows.Next() {
		var i Devices
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.DeviceName,
			&i.DeviceType,
			&i.DeviceIdentifier,
			&i.AuthToken,
			&i.LastSync,
			&i.LastSeen,
			&i.SyncEnabled,
			&i.AutoSync,
			&i.SyncFrequencyMinutes,
			&i.DeviceMetadata,
			&i.CreatedAt,
			&i.UpdatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListDevicesByUser = `-- name: ListDevicesByUser :many
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE user_id = $1 ORDER BY created_at DESC
`

func (q *Queries) ListDevicesByUser(ctx context.Context, userID pgtype.UUID) ([]Devices, error) {
	rows, err := q.db.Query(ctx, ListDevicesByUser, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []Devices{}
	for rows.Next() {
		var i Devices
		if err := rows.Scan(
			&i.ID,
			&i.UserID,
			&i.DeviceName,
			&i.DeviceType,
			&i.DeviceIdentifier,
			&i.AuthToken,
			&i.LastSync,
			&i.LastSeen,
			&i.SyncEnabled,
			&i.AutoSync,
			&i.SyncFrequencyMinutes,
			&i.DeviceMetadata,
			&i.CreatedAt,
			&i.UpdatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListLibraries = `-- name: ListLibraries :many
SELECT l.id, l.name, l.description, l.library_type_id, l.created_by_admin_id, l.created_at, l.updated_at, lt.name as type_name, lt.description as type_description
FROM libraries l
JOIN library_types lt ON l.library_type_id = lt.id
ORDER BY l.created_at DESC
`

type ListLibrariesRow struct {
	ID               pgtype.UUID        `db:"id" json:"id"`
	Name             string             `db:"name" json:"name"`
	Description      pgtype.Text        `db:"description" json:"description"`
	LibraryTypeID    pgtype.UUID        `db:"library_type_id" json:"library_type_id"`
	CreatedByAdminID pgtype.UUID        `db:"created_by_admin_id" json:"created_by_admin_id"`
	CreatedAt        pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt        pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	TypeName         string             `db:"type_name" json:"type_name"`
	TypeDescription  pgtype.Text        `db:"type_description" json:"type_description"`
}

func (q *Queries) ListLibraries(ctx context.Context) ([]ListLibrariesRow, error) {
	rows, err := q.db.Query(ctx, ListLibraries)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListLibrariesRow{}
	for rows.Next() {
		var i ListLibrariesRow
		if err := rows.Scan(
			&i.ID,
			&i.Name,
			&i.Description,
			&i.LibraryTypeID,
			&i.CreatedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.TypeName,
			&i.TypeDescription,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListMediaItems = `-- name: ListMediaItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
ORDER BY mi.created_at DESC LIMIT $1 OFFSET $2
`

type ListMediaItemsParams struct {
	Limit  int32 `db:"limit" json:"limit"`
	Offset int32 `db:"offset" json:"offset"`
}

type ListMediaItemsRow struct {
	ID                 pgtype.UUID        `db:"id" json:"id"`
	LibraryID          pgtype.UUID        `db:"library_id" json:"library_id"`
	Title              string             `db:"title" json:"title"`
	Author             pgtype.Text        `db:"author" json:"author"`
	Isbn               pgtype.Text        `db:"isbn" json:"isbn"`
	Description        pgtype.Text        `db:"description" json:"description"`
	FilePath           string             `db:"file_path" json:"file_path"`
	FileSize           pgtype.Int8        `db:"file_size" json:"file_size"`
	MimeType           pgtype.Text        `db:"mime_type" json:"mime_type"`
	CoverImagePath     pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text        `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4        `db:"series_number" json:"series_number"`
	Tags               []string           `db:"tags" json:"tags"`
	Asin               pgtype.Text        `db:"asin" json:"asin"`
	DatePublished      pgtype.Date        `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text        `db:"publisher" json:"publisher"`
	Contributors       []string           `db:"contributors" json:"contributors"`
	Language           pgtype.Text        `db:"language" json:"language"`
	Edition            pgtype.Text        `db:"edition" json:"edition"`
	PageCount          pgtype.Int4        `db:"page_count" json:"page_count"`
	Genre              pgtype.Text        `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4        `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text        `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text        `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text        `db:"google_books_id" json:"google_books_id"`
	AddedByAdminID     pgtype.UUID        `db:"added_by_admin_id" json:"added_by_admin_id"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt          pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	FormatGroup        string             `db:"format_group" json:"format_group"`
	FormatMimetype     pgtype.Text        `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable       pgtype.Bool        `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout     pgtype.Bool        `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters    pgtype.Int8        `db:"total_characters" json:"total_characters"`
	ChapterCount       pgtype.Int4        `db:"chapter_count" json:"chapter_count"`
	EntitlementID      pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber     pgtype.Int4        `db:"revision_number" json:"revision_number"`
	KoboContentID      pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	KoboMetadata       []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	TagsSearch         []string           `db:"tags_search" json:"tags_search"`
	ContributorsSearch []string           `db:"contributors_search" json:"contributors_search"`
	FileSha256         pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier      pgtype.Text        `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid            pgtype.Text        `db:"opf_uuid" json:"opf_uuid"`
	HashConfidence     pgtype.Text        `db:"hash_confidence" json:"hash_confidence"`
	LibraryName        string             `db:"library_name" json:"library_name"`
	LibraryTypeName    string             `db:"library_type_name" json:"library_type_name"`
}

func (q *Queries) ListMediaItems(ctx context.Context, arg ListMediaItemsParams) ([]ListMediaItemsRow, error) {
	rows, err := q.db.Query(ctx, ListMediaItems, arg.Limit, arg.Offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListMediaItemsRow{}
	for rows.Next() {
		var i ListMediaItemsRow
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
			&i.LibraryName,
			&i.LibraryTypeName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListMediaItemsByLibrary = `-- name: ListMediaItemsByLibrary :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
WHERE mi.library_id = $1
ORDER BY mi.created_at DESC
`

type ListMediaItemsByLibraryRow struct {
	ID                 pgtype.UUID        `db:"id" json:"id"`
	LibraryID          pgtype.UUID        `db:"library_id" json:"library_id"`
	Title              string             `db:"title" json:"title"`
	Author             pgtype.Text        `db:"author" json:"author"`
	Isbn               pgtype.Text        `db:"isbn" json:"isbn"`
	Description        pgtype.Text        `db:"description" json:"description"`
	FilePath           string             `db:"file_path" json:"file_path"`
	FileSize           pgtype.Int8        `db:"file_size" json:"file_size"`
	MimeType           pgtype.Text        `db:"mime_type" json:"mime_type"`
	CoverImagePath     pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text        `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4        `db:"series_number" json:"series_number"`
	Tags               []string           `db:"tags" json:"tags"`
	Asin               pgtype.Text        `db:"asin" json:"asin"`
	DatePublished      pgtype.Date        `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text        `db:"publisher" json:"publisher"`
	Contributors       []string           `db:"contributors" json:"contributors"`
	Language           pgtype.Text        `db:"language" json:"language"`
	Edition            pgtype.Text        `db:"edition" json:"edition"`
	PageCount          pgtype.Int4        `db:"page_count" json:"page_count"`
	Genre              pgtype.Text        `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4        `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text        `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text        `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text        `db:"google_books_id" json:"google_books_id"`
	AddedByAdminID     pgtype.UUID        `db:"added_by_admin_id" json:"added_by_admin_id"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt          pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	FormatGroup        string             `db:"format_group" json:"format_group"`
	FormatMimetype     pgtype.Text        `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable       pgtype.Bool        `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout     pgtype.Bool        `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters    pgtype.Int8        `db:"total_characters" json:"total_characters"`
	ChapterCount       pgtype.Int4        `db:"chapter_count" json:"chapter_count"`
	EntitlementID      pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber     pgtype.Int4        `db:"revision_number" json:"revision_number"`
	KoboContentID      pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	KoboMetadata       []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	TagsSearch         []string           `db:"tags_search" json:"tags_search"`
	ContributorsSearch []string           `db:"contributors_search" json:"contributors_search"`
	FileSha256         pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier      pgtype.Text        `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid            pgtype.Text        `db:"opf_uuid" json:"opf_uuid"`
	HashConfidence     pgtype.Text        `db:"hash_confidence" json:"hash_confidence"`
	LibraryName        string             `db:"library_name" json:"library_name"`
	LibraryTypeName    string             `db:"library_type_name" json:"library_type_name"`
}

func (q *Queries) ListMediaItemsByLibrary(ctx context.Context, libraryID pgtype.UUID) ([]ListMediaItemsByLibraryRow, error) {
	rows, err := q.db.Query(ctx, ListMediaItemsByLibrary, libraryID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListMediaItemsByLibraryRow{}
	for rows.Next() {
		var i ListMediaItemsByLibraryRow
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
			&i.LibraryName,
			&i.LibraryTypeName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListMediaItemsFiltered = `-- name: ListMediaItemsFiltered :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
WHERE mi.library_id = $2
  AND COALESCE(lv.is_visible, true) = true
  AND ($3 = '' OR mi.author ILIKE $3)
  AND ($4 = '' OR mi.series ILIKE $4)
  AND ($5 = '' OR mi.genre = $5)
  AND ($6 = '' OR mi.language = $6)
  AND ($7 = 0 OR mi.copyright_year >= $7)
  AND ($8 = 0 OR mi.copyright_year <= $8)
  AND ($9 = false OR mi.cover_image_path IS NOT NULL)
ORDER BY
    CASE
        WHEN $10 = 'title ASC' THEN mi.title
        ELSE ''
    END ASC,
    CASE
        WHEN $10 = 'title DESC' THEN mi.title
        ELSE ''
    END DESC,
    CASE
        WHEN $10 = 'author ASC' THEN COALESCE(mi.author, '')
        ELSE ''
    END ASC,
    CASE
        WHEN $10 = 'author DESC' THEN COALESCE(mi.author, '')
        ELSE ''
    END DESC,
    CASE
        WHEN $10 = 'created_at ASC' THEN mi.created_at
        ELSE '1970-01-01'::timestamp
    END ASC,
    CASE
        WHEN $10 = 'created_at DESC' THEN mi.created_at
        ELSE '1970-01-01'::timestamp
    END DESC,
    mi.created_at DESC
LIMIT $12 OFFSET $11
`

type ListMediaItemsFilteredParams struct {
	UserID         pgtype.UUID `db:"user_id" json:"user_id"`
	LibraryID      pgtype.UUID `db:"library_id" json:"library_id"`
	AuthorFilter   interface{} `db:"author_filter" json:"author_filter"`
	SeriesFilter   interface{} `db:"series_filter" json:"series_filter"`
	GenreFilter    interface{} `db:"genre_filter" json:"genre_filter"`
	LanguageFilter interface{} `db:"language_filter" json:"language_filter"`
	YearMin        interface{} `db:"year_min" json:"year_min"`
	YearMax        interface{} `db:"year_max" json:"year_max"`
	HasCover       interface{} `db:"has_cover" json:"has_cover"`
	Sort           interface{} `db:"sort" json:"sort"`
	Offset         pgtype.Int4 `db:"offset" json:"offset"`
	Limit          pgtype.Int4 `db:"limit" json:"limit"`
}

type ListMediaItemsFilteredRow struct {
	ID                 pgtype.UUID        `db:"id" json:"id"`
	LibraryID          pgtype.UUID        `db:"library_id" json:"library_id"`
	Title              string             `db:"title" json:"title"`
	Author             pgtype.Text        `db:"author" json:"author"`
	Isbn               pgtype.Text        `db:"isbn" json:"isbn"`
	Description        pgtype.Text        `db:"description" json:"description"`
	FilePath           string             `db:"file_path" json:"file_path"`
	FileSize           pgtype.Int8        `db:"file_size" json:"file_size"`
	MimeType           pgtype.Text        `db:"mime_type" json:"mime_type"`
	CoverImagePath     pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text        `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4        `db:"series_number" json:"series_number"`
	Tags               []string           `db:"tags" json:"tags"`
	Asin               pgtype.Text        `db:"asin" json:"asin"`
	DatePublished      pgtype.Date        `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text        `db:"publisher" json:"publisher"`
	Contributors       []string           `db:"contributors" json:"contributors"`
	Language           pgtype.Text        `db:"language" json:"language"`
	Edition            pgtype.Text        `db:"edition" json:"edition"`
	PageCount          pgtype.Int4        `db:"page_count" json:"page_count"`
	Genre              pgtype.Text        `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4        `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text        `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text        `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text        `db:"google_books_id" json:"google_books_id"`
	AddedByAdminID     pgtype.UUID        `db:"added_by_admin_id" json:"added_by_admin_id"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt          pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	FormatGroup        string             `db:"format_group" json:"format_group"`
	FormatMimetype     pgtype.Text        `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable       pgtype.Bool        `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout     pgtype.Bool        `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters    pgtype.Int8        `db:"total_characters" json:"total_characters"`
	ChapterCount       pgtype.Int4        `db:"chapter_count" json:"chapter_count"`
	EntitlementID      pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber     pgtype.Int4        `db:"revision_number" json:"revision_number"`
	KoboContentID      pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	KoboMetadata       []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	TagsSearch         []string           `db:"tags_search" json:"tags_search"`
	ContributorsSearch []string           `db:"contributors_search" json:"contributors_search"`
	FileSha256         pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier      pgtype.Text        `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid            pgtype.Text        `db:"opf_uuid" json:"opf_uuid"`
	HashConfidence     pgtype.Text        `db:"hash_confidence" json:"hash_confidence"`
	LibraryName        string             `db:"library_name" json:"library_name"`
	LibraryTypeName    string             `db:"library_type_name" json:"library_type_name"`
}

func (q *Queries) ListMediaItemsFiltered(ctx context.Context, arg ListMediaItemsFilteredParams) ([]ListMediaItemsFilteredRow, error) {
	rows, err := q.db.Query(ctx, ListMediaItemsFiltered,
		arg.UserID,
		arg.LibraryID,
		arg.AuthorFilter,
		arg.SeriesFilter,
		arg.GenreFilter,
		arg.LanguageFilter,
		arg.YearMin,
		arg.YearMax,
		arg.HasCover,
		arg.Sort,
		arg.Offset,
		arg.Limit,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListMediaItemsFilteredRow{}
	for rows.Next() {
		var i ListMediaItemsFilteredRow
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
			&i.LibraryName,
			&i.LibraryTypeName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListMediaItemsSorted = `-- name: ListMediaItemsSorted :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
WHERE mi.library_id = $1
ORDER BY
    CASE
        WHEN $2 = 'title ASC' THEN mi.title
        ELSE ''
    END ASC,
    CASE
        WHEN $2 = 'title DESC' THEN mi.title
        ELSE ''
    END DESC,
    CASE
        WHEN $2 = 'author ASC' THEN COALESCE(mi.author, '')
        ELSE ''
    END ASC,
    CASE
        WHEN $2 = 'author DESC' THEN COALESCE(mi.author, '')
        ELSE ''
    END DESC,
    CASE
        WHEN $2 = 'created_at ASC' THEN mi.created_at
        ELSE '1970-01-01'::timestamp
    END ASC,
    CASE
        WHEN $2 = 'created_at DESC' THEN mi.created_at
        ELSE '1970-01-01'::timestamp
    END DESC,
    CASE
        WHEN $2 = 'series ASC' THEN COALESCE(mi.series, '')
        ELSE ''
    END ASC,
    CASE
        WHEN $2 = 'series DESC' THEN COALESCE(mi.series, '')
        ELSE ''
    END DESC,
    CASE
        WHEN $2 = 'date_published ASC' THEN COALESCE(mi.date_published::text, '')
        ELSE ''
    END ASC,
    CASE
        WHEN $2 = 'date_published DESC' THEN COALESCE(mi.date_published::text, '')
        ELSE ''
    END DESC,
    CASE
        WHEN $2 = 'copyright_year ASC' THEN COALESCE(mi.copyright_year::text, '0')
        ELSE ''
    END ASC,
    CASE
        WHEN $2 = 'copyright_year DESC' THEN COALESCE(mi.copyright_year::text, '0')
        ELSE ''
    END DESC,
    CASE
        WHEN $2 = 'page_count ASC' THEN COALESCE(mi.page_count::text, '0')
        ELSE ''
    END ASC,
    CASE
        WHEN $2 = 'page_count DESC' THEN COALESCE(mi.page_count::text, '0')
        ELSE ''
    END DESC,
    CASE
        WHEN $2 = 'genre ASC' THEN COALESCE(mi.genre, '')
        ELSE ''
    END ASC,
    CASE
        WHEN $2 = 'genre DESC' THEN COALESCE(mi.genre, '')
        ELSE ''
    END DESC,
    mi.created_at DESC
 LIMIT $4 OFFSET $3
`

type ListMediaItemsSortedParams struct {
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
	Sort      interface{} `db:"sort" json:"sort"`
	Offset    pgtype.Int4 `db:"offset" json:"offset"`
	Limit     pgtype.Int4 `db:"limit" json:"limit"`
}

type ListMediaItemsSortedRow struct {
	ID                 pgtype.UUID        `db:"id" json:"id"`
	LibraryID          pgtype.UUID        `db:"library_id" json:"library_id"`
	Title              string             `db:"title" json:"title"`
	Author             pgtype.Text        `db:"author" json:"author"`
	Isbn               pgtype.Text        `db:"isbn" json:"isbn"`
	Description        pgtype.Text        `db:"description" json:"description"`
	FilePath           string             `db:"file_path" json:"file_path"`
	FileSize           pgtype.Int8        `db:"file_size" json:"file_size"`
	MimeType           pgtype.Text        `db:"mime_type" json:"mime_type"`
	CoverImagePath     pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text        `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4        `db:"series_number" json:"series_number"`
	Tags               []string           `db:"tags" json:"tags"`
	Asin               pgtype.Text        `db:"asin" json:"asin"`
	DatePublished      pgtype.Date        `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text        `db:"publisher" json:"publisher"`
	Contributors       []string           `db:"contributors" json:"contributors"`
	Language           pgtype.Text        `db:"language" json:"language"`
	Edition            pgtype.Text        `db:"edition" json:"edition"`
	PageCount          pgtype.Int4        `db:"page_count" json:"page_count"`
	Genre              pgtype.Text        `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4        `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text        `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text        `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text        `db:"google_books_id" json:"google_books_id"`
	AddedByAdminID     pgtype.UUID        `db:"added_by_admin_id" json:"added_by_admin_id"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt          pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	FormatGroup        string             `db:"format_group" json:"format_group"`
	FormatMimetype     pgtype.Text        `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable       pgtype.Bool        `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout     pgtype.Bool        `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters    pgtype.Int8        `db:"total_characters" json:"total_characters"`
	ChapterCount       pgtype.Int4        `db:"chapter_count" json:"chapter_count"`
	EntitlementID      pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber     pgtype.Int4        `db:"revision_number" json:"revision_number"`
	KoboContentID      pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	KoboMetadata       []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	TagsSearch         []string           `db:"tags_search" json:"tags_search"`
	ContributorsSearch []string           `db:"contributors_search" json:"contributors_search"`
	FileSha256         pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier      pgtype.Text        `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid            pgtype.Text        `db:"opf_uuid" json:"opf_uuid"`
	HashConfidence     pgtype.Text        `db:"hash_confidence" json:"hash_confidence"`
	LibraryName        string             `db:"library_name" json:"library_name"`
	LibraryTypeName    string             `db:"library_type_name" json:"library_type_name"`
}

func (q *Queries) ListMediaItemsSorted(ctx context.Context, arg ListMediaItemsSortedParams) ([]ListMediaItemsSortedRow, error) {
	rows, err := q.db.Query(ctx, ListMediaItemsSorted,
		arg.LibraryID,
		arg.Sort,
		arg.Offset,
		arg.Limit,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListMediaItemsSortedRow{}
	for rows.Next() {
		var i ListMediaItemsSortedRow
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
			&i.LibraryName,
			&i.LibraryTypeName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListPendingSyncQueueItems = `-- name: ListPendingSyncQueueItems :many
SELECT id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at FROM sync_queue
WHERE device_id = $1 AND status = 'pending'
ORDER BY priority ASC, created_at ASC
LIMIT $2
`

type ListPendingSyncQueueItemsParams struct {
	DeviceID pgtype.UUID `db:"device_id" json:"device_id"`
	Limit    int32       `db:"limit" json:"limit"`
}

func (q *Queries) ListPendingSyncQueueItems(ctx context.Context, arg ListPendingSyncQueueItemsParams) ([]SyncQueue, error) {
	rows, err := q.db.Query(ctx, ListPendingSyncQueueItems, arg.DeviceID, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []SyncQueue{}
	for rows.Next() {
		var i SyncQueue
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.MediaItemID,
			&i.SyncType,
			&i.SyncData,
			&i.Priority,
			&i.Attempts,
			&i.MaxAttempts,
			&i.Status,
			&i.ErrorMessage,
			&i.CreatedAt,
			&i.ProcessedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListSyncConflictsByMediaItem = `-- name: ListSyncConflictsByMediaItem :many
SELECT id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at FROM sync_conflicts
WHERE media_item_id = $1 AND user_id = $2
ORDER BY created_at DESC
`

type ListSyncConflictsByMediaItemParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
}

func (q *Queries) ListSyncConflictsByMediaItem(ctx context.Context, arg ListSyncConflictsByMediaItemParams) ([]SyncConflicts, error) {
	rows, err := q.db.Query(ctx, ListSyncConflictsByMediaItem, arg.MediaItemID, arg.UserID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []SyncConflicts{}
	for rows.Next() {
		var i SyncConflicts
		if err := rows.Scan(
			&i.ID,
			&i.MediaItemID,
			&i.UserID,
			&i.ConflictType,
			&i.ConflictData,
			&i.ResolutionStatus,
			&i.ResolutionData,
			&i.ResolvedBy,
			&i.ResolvedAt,
			&i.CreatedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListSyncConflictsByUser = `-- name: ListSyncConflictsByUser :many
SELECT sc.id, sc.media_item_id, sc.user_id, sc.conflict_type, sc.conflict_data, sc.resolution_status, sc.resolution_data, sc.resolved_by, sc.resolved_at, sc.created_at, mi.title, mi.author
FROM sync_conflicts sc
JOIN media_items mi ON sc.media_item_id = mi.id
WHERE sc.user_id = $1 AND sc.resolution_status = 'unresolved'
ORDER BY sc.created_at DESC
`

type ListSyncConflictsByUserRow struct {
	ID               pgtype.UUID        `db:"id" json:"id"`
	MediaItemID      pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	UserID           pgtype.UUID        `db:"user_id" json:"user_id"`
	ConflictType     string             `db:"conflict_type" json:"conflict_type"`
	ConflictData     []byte             `db:"conflict_data" json:"conflict_data"`
	ResolutionStatus pgtype.Text        `db:"resolution_status" json:"resolution_status"`
	ResolutionData   []byte             `db:"resolution_data" json:"resolution_data"`
	ResolvedBy       pgtype.UUID        `db:"resolved_by" json:"resolved_by"`
	ResolvedAt       pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
	CreatedAt        pgtype.Timestamptz `db:"created_at" json:"created_at"`
	Title            string             `db:"title" json:"title"`
	Author           pgtype.Text        `db:"author" json:"author"`
}

func (q *Queries) ListSyncConflictsByUser(ctx context.Context, userID pgtype.UUID) ([]ListSyncConflictsByUserRow, error) {
	rows, err := q.db.Query(ctx, ListSyncConflictsByUser, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListSyncConflictsByUserRow{}
	for rows.Next() {
		var i ListSyncConflictsByUserRow
		if err := rows.Scan(
			&i.ID,
			&i.MediaItemID,
			&i.UserID,
			&i.ConflictType,
			&i.ConflictData,
			&i.ResolutionStatus,
			&i.ResolutionData,
			&i.ResolvedBy,
			&i.ResolvedAt,
			&i.CreatedAt,
			&i.Title,
			&i.Author,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListUnresolvedUnlinkedBooks = `-- name: ListUnresolvedUnlinkedBooks :many
SELECT ub.id, ub.device_id, ub.content_id, ub.file_path, ub.title, ub.author, ub.confidence_score, ub.resolved, ub.media_item_id, ub.resolved_at, ub.resolution_method, ub.last_seen_at, ub.created_at, d.device_name, d.device_type
FROM unlinked_books ub
JOIN devices d ON ub.device_id = d.id
WHERE ub.resolved = false
ORDER BY ub.last_seen_at DESC
LIMIT $1 OFFSET $2
`

type ListUnresolvedUnlinkedBooksParams struct {
	Limit  int32 `db:"limit" json:"limit"`
	Offset int32 `db:"offset" json:"offset"`
}

type ListUnresolvedUnlinkedBooksRow struct {
	ID               pgtype.UUID        `db:"id" json:"id"`
	DeviceID         pgtype.UUID        `db:"device_id" json:"device_id"`
	ContentID        string             `db:"content_id" json:"content_id"`
	FilePath         pgtype.Text        `db:"file_path" json:"file_path"`
	Title            pgtype.Text        `db:"title" json:"title"`
	Author           pgtype.Text        `db:"author" json:"author"`
	ConfidenceScore  pgtype.Float8      `db:"confidence_score" json:"confidence_score"`
	Resolved         pgtype.Bool        `db:"resolved" json:"resolved"`
	MediaItemID      pgtype.UUID        `db:"media_item_id" json:"media_item_id"`
	ResolvedAt       pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
	ResolutionMethod pgtype.Text        `db:"resolution_method" json:"resolution_method"`
	LastSeenAt       pgtype.Timestamptz `db:"last_seen_at" json:"last_seen_at"`
	CreatedAt        pgtype.Timestamptz `db:"created_at" json:"created_at"`
	DeviceName       string             `db:"device_name" json:"device_name"`
	DeviceType       string             `db:"device_type" json:"device_type"`
}

// List unresolved unlinked books with pagination
func (q *Queries) ListUnresolvedUnlinkedBooks(ctx context.Context, arg ListUnresolvedUnlinkedBooksParams) ([]ListUnresolvedUnlinkedBooksRow, error) {
	rows, err := q.db.Query(ctx, ListUnresolvedUnlinkedBooks, arg.Limit, arg.Offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListUnresolvedUnlinkedBooksRow{}
	for rows.Next() {
		var i ListUnresolvedUnlinkedBooksRow
		if err := rows.Scan(
			&i.ID,
			&i.DeviceID,
			&i.ContentID,
			&i.FilePath,
			&i.Title,
			&i.Author,
			&i.ConfidenceScore,
			&i.Resolved,
			&i.MediaItemID,
			&i.ResolvedAt,
			&i.ResolutionMethod,
			&i.LastSeenAt,
			&i.CreatedAt,
			&i.DeviceName,
			&i.DeviceType,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const ListUsers = `-- name: ListUsers :many
SELECT
    u.id,
    u.email,
    u.username,
    u.theme,
    u.first_name,
    u.last_name,
    u.role,
    u.max_devices,
    u.created_at,
    u.updated_at,
    (SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count
FROM users u
ORDER BY u.created_at DESC
`

type ListUsersRow struct {
	ID          pgtype.UUID        `db:"id" json:"id"`
	Email       string             `db:"email" json:"email"`
	Username    string             `db:"username" json:"username"`
	Theme       pgtype.Text        `db:"theme" json:"theme"`
	FirstName   pgtype.Text        `db:"first_name" json:"first_name"`
	LastName    pgtype.Text        `db:"last_name" json:"last_name"`
	Role        string             `db:"role" json:"role"`
	MaxDevices  pgtype.Int4        `db:"max_devices" json:"max_devices"`
	CreatedAt   pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt   pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	DeviceCount int64              `db:"device_count" json:"device_count"`
}

func (q *Queries) ListUsers(ctx context.Context) ([]ListUsersRow, error) {
	rows, err := q.db.Query(ctx, ListUsers)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []ListUsersRow{}
	for rows.Next() {
		var i ListUsersRow
		if err := rows.Scan(
			&i.ID,
			&i.Email,
			&i.Username,
			&i.Theme,
			&i.FirstName,
			&i.LastName,
			&i.Role,
			&i.MaxDevices,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DeviceCount,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const QueryMediaItemsByIdentifiers = `-- name: QueryMediaItemsByIdentifiers :many
SELECT
    mi.id,
    mi.file_sha256,
    mi.opf_identifier,
    mi.opf_uuid,
    mi.isbn,
    mi.asin,
    mi.title,
    mi.author,
    mi.file_size,
    mi.hash_confidence,
    CASE
        WHEN $1::uuid IS NOT NULL AND mi.id = $1::uuid THEN 1.0
        WHEN mi.opf_uuid IS NOT NULL AND mi.opf_uuid = $2::text THEN 0.95
        WHEN mi.file_sha256 IS NOT NULL AND mi.file_sha256 = $3::text THEN 0.9
        WHEN mi.opf_identifier IS NOT NULL AND mi.opf_identifier = $4::text THEN 0.85
        WHEN mi.isbn IS NOT NULL AND mi.isbn = $5::text THEN 0.8
        WHEN mi.asin IS NOT NULL AND mi.asin = $6::text THEN 0.8
        ELSE 0.5
    END as confidence_score
FROM media_items mi
WHERE
    ($1::uuid IS NULL OR mi.id = $1::uuid)
    OR ($2::text IS NULL OR mi.opf_uuid = $2::text)
    OR ($3::text IS NULL OR mi.file_sha256 = $3::text)
    OR ($4::text IS NULL OR mi.opf_identifier = $4::text)
    OR ($5::text IS NULL OR mi.isbn = $5::text)
    OR ($6::text IS NULL OR mi.asin = $6::text)
    OR ($7::text IS NULL OR mi.title ILIKE '%' || $7::text || '%')
ORDER BY confidence_score DESC
`

type QueryMediaItemsByIdentifiersParams struct {
	Column1 pgtype.UUID `db:"column_1" json:"column_1"`
	Column2 string      `db:"column_2" json:"column_2"`
	Column3 string      `db:"column_3" json:"column_3"`
	Column4 string      `db:"column_4" json:"column_4"`
	Column5 string      `db:"column_5" json:"column_5"`
	Column6 string      `db:"column_6" json:"column_6"`
	Column7 string      `db:"column_7" json:"column_7"`
}

type QueryMediaItemsByIdentifiersRow struct {
	ID              pgtype.UUID `db:"id" json:"id"`
	FileSha256      pgtype.Text `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier   pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid         pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
	Isbn            pgtype.Text `db:"isbn" json:"isbn"`
	Asin            pgtype.Text `db:"asin" json:"asin"`
	Title           string      `db:"title" json:"title"`
	Author          pgtype.Text `db:"author" json:"author"`
	FileSize        pgtype.Int8 `db:"file_size" json:"file_size"`
	HashConfidence  pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
	ConfidenceScore float64     `db:"confidence_score" json:"confidence_score"`
}

// Query media items by multiple identifiers with confidence scoring
func (q *Queries) QueryMediaItemsByIdentifiers(ctx context.Context, arg QueryMediaItemsByIdentifiersParams) ([]QueryMediaItemsByIdentifiersRow, error) {
	rows, err := q.db.Query(ctx, QueryMediaItemsByIdentifiers,
		arg.Column1,
		arg.Column2,
		arg.Column3,
		arg.Column4,
		arg.Column5,
		arg.Column6,
		arg.Column7,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []QueryMediaItemsByIdentifiersRow{}
	for rows.Next() {
		var i QueryMediaItemsByIdentifiersRow
		if err := rows.Scan(
			&i.ID,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.Isbn,
			&i.Asin,
			&i.Title,
			&i.Author,
			&i.FileSize,
			&i.HashConfidence,
			&i.ConfidenceScore,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const RemoveBookFromCollection = `-- name: RemoveBookFromCollection :exec
DELETE FROM collection_items WHERE collection_id = $1 AND media_item_id = $2
`

type RemoveBookFromCollectionParams struct {
	CollectionID pgtype.UUID `db:"collection_id" json:"collection_id"`
	MediaItemID  pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}

// Remove book from collection
func (q *Queries) RemoveBookFromCollection(ctx context.Context, arg RemoveBookFromCollectionParams) error {
	_, err := q.db.Exec(ctx, RemoveBookFromCollection, arg.CollectionID, arg.MediaItemID)
	return err
}

const RemoveBookFromKoboShelf = `-- name: RemoveBookFromKoboShelf :exec
DELETE FROM kobo_shelves WHERE device_id = $1 AND media_item_id = $2
`

type RemoveBookFromKoboShelfParams struct {
	DeviceID    pgtype.UUID `db:"device_id" json:"device_id"`
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
}

func (q *Queries) RemoveBookFromKoboShelf(ctx context.Context, arg RemoveBookFromKoboShelfParams) error {
	_, err := q.db.Exec(ctx, RemoveBookFromKoboShelf, arg.DeviceID, arg.MediaItemID)
	return err
}

const ResetSystemCollectionMetadata = `-- name: ResetSystemCollectionMetadata :exec
UPDATE collections
SET description = $3,
    icon = $4,
    color = $5,
    priority = $6
WHERE user_id = $1
  AND name = $2
  AND is_system_collection = true
`

type ResetSystemCollectionMetadataParams struct {
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
	Name        string      `db:"name" json:"name"`
	Description pgtype.Text `db:"description" json:"description"`
	Icon        pgtype.Text `db:"icon" json:"icon"`
	Color       pgtype.Text `db:"color" json:"color"`
	Priority    pgtype.Int4 `db:"priority" json:"priority"`
}

func (q *Queries) ResetSystemCollectionMetadata(ctx context.Context, arg ResetSystemCollectionMetadataParams) error {
	_, err := q.db.Exec(ctx, ResetSystemCollectionMetadata,
		arg.UserID,
		arg.Name,
		arg.Description,
		arg.Icon,
		arg.Color,
		arg.Priority,
	)
	return err
}

const ResolveSyncConflict = `-- name: ResolveSyncConflict :one
UPDATE sync_conflicts
SET
    resolution_status = $2,
    resolution_data = $3,
    resolved_by = $4,
    resolved_at = NOW()
WHERE id = $1
RETURNING id, media_item_id, user_id, conflict_type, conflict_data, resolution_status, resolution_data, resolved_by, resolved_at, created_at
`

type ResolveSyncConflictParams struct {
	ID               pgtype.UUID `db:"id" json:"id"`
	ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"`
	ResolutionData   []byte      `db:"resolution_data" json:"resolution_data"`
	ResolvedBy       pgtype.UUID `db:"resolved_by" json:"resolved_by"`
}

func (q *Queries) ResolveSyncConflict(ctx context.Context, arg ResolveSyncConflictParams) (SyncConflicts, error) {
	row := q.db.QueryRow(ctx, ResolveSyncConflict,
		arg.ID,
		arg.ResolutionStatus,
		arg.ResolutionData,
		arg.ResolvedBy,
	)
	var i SyncConflicts
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.ConflictType,
		&i.ConflictData,
		&i.ResolutionStatus,
		&i.ResolutionData,
		&i.ResolvedBy,
		&i.ResolvedAt,
		&i.CreatedAt,
	)
	return i, err
}

const ResolveUnlinkedBook = `-- name: ResolveUnlinkedBook :one
UPDATE unlinked_books
SET
    resolved = true,
    media_item_id = $2,
    resolved_at = NOW(),
    resolution_method = $3
WHERE id = $1
RETURNING id, device_id, content_id, file_path, title, author, confidence_score, resolved, media_item_id, resolved_at, resolution_method, last_seen_at, created_at
`

type ResolveUnlinkedBookParams struct {
	ID               pgtype.UUID `db:"id" json:"id"`
	MediaItemID      pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	ResolutionMethod pgtype.Text `db:"resolution_method" json:"resolution_method"`
}

// Resolve unlinked book
func (q *Queries) ResolveUnlinkedBook(ctx context.Context, arg ResolveUnlinkedBookParams) (UnlinkedBooks, error) {
	row := q.db.QueryRow(ctx, ResolveUnlinkedBook, arg.ID, arg.MediaItemID, arg.ResolutionMethod)
	var i UnlinkedBooks
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.ContentID,
		&i.FilePath,
		&i.Title,
		&i.Author,
		&i.ConfidenceScore,
		&i.Resolved,
		&i.MediaItemID,
		&i.ResolvedAt,
		&i.ResolutionMethod,
		&i.LastSeenAt,
		&i.CreatedAt,
	)
	return i, err
}

const RevokeAllUserRefreshTokens = `-- name: RevokeAllUserRefreshTokens :exec
UPDATE refresh_tokens SET revoked_at = NOW() WHERE user_id = $1 AND revoked_at IS NULL
`

func (q *Queries) RevokeAllUserRefreshTokens(ctx context.Context, userID pgtype.UUID) error {
	_, err := q.db.Exec(ctx, RevokeAllUserRefreshTokens, userID)
	return err
}

const RevokeDevice = `-- name: RevokeDevice :exec
UPDATE devices
SET
    auth_token = NULL,
    sync_enabled = false,
    updated_at = NOW()
WHERE id = $1
`

func (q *Queries) RevokeDevice(ctx context.Context, id pgtype.UUID) error {
	_, err := q.db.Exec(ctx, RevokeDevice, id)
	return err
}

const RevokeOpdsToken = `-- name: RevokeOpdsToken :exec
DELETE FROM opds_tokens WHERE token = $1
`

// Revoke OPDS token
func (q *Queries) RevokeOpdsToken(ctx context.Context, token string) error {
	_, err := q.db.Exec(ctx, RevokeOpdsToken, token)
	return err
}

const RevokeRefreshToken = `-- name: RevokeRefreshToken :exec
UPDATE refresh_tokens SET revoked_at = NOW() WHERE token = $1
`

func (q *Queries) RevokeRefreshToken(ctx context.Context, token pgtype.UUID) error {
	_, err := q.db.Exec(ctx, RevokeRefreshToken, token)
	return err
}

const SearchMediaItems = `-- name: SearchMediaItems :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
 WHERE COALESCE(lv.is_visible, true) = true
   AND ($2 IS NULL OR mi.library_id = $2)
   AND (
       mi.title ILIKE $3 OR
       mi.author ILIKE $3 OR
        mi.series ILIKE $3 OR
        $3 = ANY(mi.tags_search) OR
        $3 = ANY(mi.contributors_search)
   )
 ORDER BY
    CASE
       WHEN mi.title ILIKE $3 THEN 1
       WHEN mi.author ILIKE $3 THEN 2
       WHEN mi.series ILIKE $3 THEN 3
       WHEN $3 = ANY(mi.tags_search) THEN 4
       ELSE 5
   END,
  mi.title ASC
LIMIT $5 OFFSET $4
`

type SearchMediaItemsParams struct {
	UserID        pgtype.UUID `db:"user_id" json:"user_id"`
	LibraryID     interface{} `db:"library_id" json:"library_id"`
	SearchPattern pgtype.Text `db:"search_pattern" json:"search_pattern"`
	Offset        pgtype.Int4 `db:"offset" json:"offset"`
	Limit         pgtype.Int4 `db:"limit" json:"limit"`
}

type SearchMediaItemsRow struct {
	ID                 pgtype.UUID        `db:"id" json:"id"`
	LibraryID          pgtype.UUID        `db:"library_id" json:"library_id"`
	Title              string             `db:"title" json:"title"`
	Author             pgtype.Text        `db:"author" json:"author"`
	Isbn               pgtype.Text        `db:"isbn" json:"isbn"`
	Description        pgtype.Text        `db:"description" json:"description"`
	FilePath           string             `db:"file_path" json:"file_path"`
	FileSize           pgtype.Int8        `db:"file_size" json:"file_size"`
	MimeType           pgtype.Text        `db:"mime_type" json:"mime_type"`
	CoverImagePath     pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text        `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4        `db:"series_number" json:"series_number"`
	Tags               []string           `db:"tags" json:"tags"`
	Asin               pgtype.Text        `db:"asin" json:"asin"`
	DatePublished      pgtype.Date        `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text        `db:"publisher" json:"publisher"`
	Contributors       []string           `db:"contributors" json:"contributors"`
	Language           pgtype.Text        `db:"language" json:"language"`
	Edition            pgtype.Text        `db:"edition" json:"edition"`
	PageCount          pgtype.Int4        `db:"page_count" json:"page_count"`
	Genre              pgtype.Text        `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4        `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text        `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text        `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text        `db:"google_books_id" json:"google_books_id"`
	AddedByAdminID     pgtype.UUID        `db:"added_by_admin_id" json:"added_by_admin_id"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt          pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	FormatGroup        string             `db:"format_group" json:"format_group"`
	FormatMimetype     pgtype.Text        `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable       pgtype.Bool        `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout     pgtype.Bool        `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters    pgtype.Int8        `db:"total_characters" json:"total_characters"`
	ChapterCount       pgtype.Int4        `db:"chapter_count" json:"chapter_count"`
	EntitlementID      pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber     pgtype.Int4        `db:"revision_number" json:"revision_number"`
	KoboContentID      pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	KoboMetadata       []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	TagsSearch         []string           `db:"tags_search" json:"tags_search"`
	ContributorsSearch []string           `db:"contributors_search" json:"contributors_search"`
	FileSha256         pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier      pgtype.Text        `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid            pgtype.Text        `db:"opf_uuid" json:"opf_uuid"`
	HashConfidence     pgtype.Text        `db:"hash_confidence" json:"hash_confidence"`
	LibraryName        string             `db:"library_name" json:"library_name"`
	LibraryTypeName    string             `db:"library_type_name" json:"library_type_name"`
}

// Search Media Items queries
func (q *Queries) SearchMediaItems(ctx context.Context, arg SearchMediaItemsParams) ([]SearchMediaItemsRow, error) {
	rows, err := q.db.Query(ctx, SearchMediaItems,
		arg.UserID,
		arg.LibraryID,
		arg.SearchPattern,
		arg.Offset,
		arg.Limit,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []SearchMediaItemsRow{}
	for rows.Next() {
		var i SearchMediaItemsRow
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
			&i.LibraryName,
			&i.LibraryTypeName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const SearchMediaItemsFuzzy = `-- name: SearchMediaItemsFuzzy :many
SELECT mi.id, mi.library_id, mi.title, mi.author, mi.isbn, mi.description, mi.file_path, mi.file_size, mi.mime_type, mi.cover_image_path, mi.series, mi.series_number, mi.tags, mi.asin, mi.date_published, mi.publisher, mi.contributors, mi.language, mi.edition, mi.page_count, mi.genre, mi.copyright_year, mi.goodreads_id, mi.openlibrary_id, mi.google_books_id, mi.added_by_admin_id, mi.created_at, mi.updated_at, mi.format_group, mi.format_mimetype, mi.is_reflowable, mi.has_fixed_layout, mi.total_characters, mi.chapter_count, mi.entitlement_id, mi.revision_number, mi.kobo_content_id, mi.kobo_metadata, mi.tags_search, mi.contributors_search, mi.file_sha256, mi.opf_identifier, mi.opf_uuid, mi.hash_confidence, l.name as library_name, lt.name as library_type_name
FROM media_items mi
JOIN libraries l ON mi.library_id = l.id
JOIN library_types lt ON l.library_type_id = lt.id
LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1
WHERE COALESCE(lv.is_visible, true) = true
   AND ($2 IS NULL OR mi.library_id = $2)
   AND (
       word_similarity($3, mi.title) > 0.3 OR
       word_similarity($3, COALESCE(mi.author, '')) > 0.3 OR
       word_similarity($3, COALESCE(mi.series, '')) > 0.3 OR
       EXISTS (
         SELECT 1 FROM unnest(mi.tags_search) AS tag
         WHERE word_similarity($3, tag) > 0.3
         LIMIT 1
       ) OR
       EXISTS (
         SELECT 1 FROM unnest(mi.contributors_search) AS contributor
         WHERE word_similarity($3, contributor) > 0.3
         LIMIT 1
       )
   )
 ORDER BY
   GREATEST(
       word_similarity($3, mi.title),
       word_similarity($3, COALESCE(mi.author, '')),
       word_similarity($3, COALESCE(mi.series, '')),
       COALESCE(
         (SELECT MAX(word_similarity($3, tag))
          FROM unnest(mi.tags_search) AS tag),
         0
       ),
       COALESCE(
         (SELECT MAX(word_similarity($3, contributor))
          FROM unnest(mi.contributors_search) AS contributor),
         0
       )
   ) DESC,
   mi.title ASC
 LIMIT $5 OFFSET $4
`

type SearchMediaItemsFuzzyParams struct {
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
	LibraryID   interface{} `db:"library_id" json:"library_id"`
	SearchQuery interface{} `db:"search_query" json:"search_query"`
	Offset      pgtype.Int4 `db:"offset" json:"offset"`
	Limit       pgtype.Int4 `db:"limit" json:"limit"`
}

type SearchMediaItemsFuzzyRow struct {
	ID                 pgtype.UUID        `db:"id" json:"id"`
	LibraryID          pgtype.UUID        `db:"library_id" json:"library_id"`
	Title              string             `db:"title" json:"title"`
	Author             pgtype.Text        `db:"author" json:"author"`
	Isbn               pgtype.Text        `db:"isbn" json:"isbn"`
	Description        pgtype.Text        `db:"description" json:"description"`
	FilePath           string             `db:"file_path" json:"file_path"`
	FileSize           pgtype.Int8        `db:"file_size" json:"file_size"`
	MimeType           pgtype.Text        `db:"mime_type" json:"mime_type"`
	CoverImagePath     pgtype.Text        `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text        `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4        `db:"series_number" json:"series_number"`
	Tags               []string           `db:"tags" json:"tags"`
	Asin               pgtype.Text        `db:"asin" json:"asin"`
	DatePublished      pgtype.Date        `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text        `db:"publisher" json:"publisher"`
	Contributors       []string           `db:"contributors" json:"contributors"`
	Language           pgtype.Text        `db:"language" json:"language"`
	Edition            pgtype.Text        `db:"edition" json:"edition"`
	PageCount          pgtype.Int4        `db:"page_count" json:"page_count"`
	Genre              pgtype.Text        `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4        `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text        `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text        `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text        `db:"google_books_id" json:"google_books_id"`
	AddedByAdminID     pgtype.UUID        `db:"added_by_admin_id" json:"added_by_admin_id"`
	CreatedAt          pgtype.Timestamptz `db:"created_at" json:"created_at"`
	UpdatedAt          pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
	FormatGroup        string             `db:"format_group" json:"format_group"`
	FormatMimetype     pgtype.Text        `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable       pgtype.Bool        `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout     pgtype.Bool        `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters    pgtype.Int8        `db:"total_characters" json:"total_characters"`
	ChapterCount       pgtype.Int4        `db:"chapter_count" json:"chapter_count"`
	EntitlementID      pgtype.Text        `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber     pgtype.Int4        `db:"revision_number" json:"revision_number"`
	KoboContentID      pgtype.Text        `db:"kobo_content_id" json:"kobo_content_id"`
	KoboMetadata       []byte             `db:"kobo_metadata" json:"kobo_metadata"`
	TagsSearch         []string           `db:"tags_search" json:"tags_search"`
	ContributorsSearch []string           `db:"contributors_search" json:"contributors_search"`
	FileSha256         pgtype.Text        `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier      pgtype.Text        `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid            pgtype.Text        `db:"opf_uuid" json:"opf_uuid"`
	HashConfidence     pgtype.Text        `db:"hash_confidence" json:"hash_confidence"`
	LibraryName        string             `db:"library_name" json:"library_name"`
	LibraryTypeName    string             `db:"library_type_name" json:"library_type_name"`
}

func (q *Queries) SearchMediaItemsFuzzy(ctx context.Context, arg SearchMediaItemsFuzzyParams) ([]SearchMediaItemsFuzzyRow, error) {
	rows, err := q.db.Query(ctx, SearchMediaItemsFuzzy,
		arg.UserID,
		arg.LibraryID,
		arg.SearchQuery,
		arg.Offset,
		arg.Limit,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []SearchMediaItemsFuzzyRow{}
	for rows.Next() {
		var i SearchMediaItemsFuzzyRow
		if err := rows.Scan(
			&i.ID,
			&i.LibraryID,
			&i.Title,
			&i.Author,
			&i.Isbn,
			&i.Description,
			&i.FilePath,
			&i.FileSize,
			&i.MimeType,
			&i.CoverImagePath,
			&i.Series,
			&i.SeriesNumber,
			&i.Tags,
			&i.Asin,
			&i.DatePublished,
			&i.Publisher,
			&i.Contributors,
			&i.Language,
			&i.Edition,
			&i.PageCount,
			&i.Genre,
			&i.CopyrightYear,
			&i.GoodreadsID,
			&i.OpenlibraryID,
			&i.GoogleBooksID,
			&i.AddedByAdminID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.FormatGroup,
			&i.FormatMimetype,
			&i.IsReflowable,
			&i.HasFixedLayout,
			&i.TotalCharacters,
			&i.ChapterCount,
			&i.EntitlementID,
			&i.RevisionNumber,
			&i.KoboContentID,
			&i.KoboMetadata,
			&i.TagsSearch,
			&i.ContributorsSearch,
			&i.FileSha256,
			&i.OpfIdentifier,
			&i.OpfUuid,
			&i.HashConfidence,
			&i.LibraryName,
			&i.LibraryTypeName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const SetLibraryVisibility = `-- name: SetLibraryVisibility :one
INSERT INTO library_visibility (user_id, library_id, is_visible)
VALUES ($1, $2, $3)
ON CONFLICT (user_id, library_id)
DO UPDATE SET
    is_visible = EXCLUDED.is_visible,
    updated_at = NOW()
RETURNING id, user_id, library_id, is_visible, created_at, updated_at
`

type SetLibraryVisibilityParams struct {
	UserID    pgtype.UUID `db:"user_id" json:"user_id"`
	LibraryID pgtype.UUID `db:"library_id" json:"library_id"`
	IsVisible bool        `db:"is_visible" json:"is_visible"`
}

// Library Visibility queries
func (q *Queries) SetLibraryVisibility(ctx context.Context, arg SetLibraryVisibilityParams) (LibraryVisibility, error) {
	row := q.db.QueryRow(ctx, SetLibraryVisibility, arg.UserID, arg.LibraryID, arg.IsVisible)
	var i LibraryVisibility
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.LibraryID,
		&i.IsVisible,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const SetSystemConfig = `-- name: SetSystemConfig :one
INSERT INTO system_config (key, value, updated_by)
VALUES ($1, $2, $3)
ON CONFLICT (key)
DO UPDATE SET
    value = EXCLUDED.value,
    updated_by = EXCLUDED.updated_by,
    updated_at = NOW()
RETURNING key, value, updated_at, updated_by
`

type SetSystemConfigParams struct {
	Key       string      `db:"key" json:"key"`
	Value     string      `db:"value" json:"value"`
	UpdatedBy pgtype.UUID `db:"updated_by" json:"updated_by"`
}

// Set system config
func (q *Queries) SetSystemConfig(ctx context.Context, arg SetSystemConfigParams) (SystemConfig, error) {
	row := q.db.QueryRow(ctx, SetSystemConfig, arg.Key, arg.Value, arg.UpdatedBy)
	var i SystemConfig
	err := row.Scan(
		&i.Key,
		&i.Value,
		&i.UpdatedAt,
		&i.UpdatedBy,
	)
	return i, err
}

const UpdateCollection = `-- name: UpdateCollection :one
UPDATE collections
SET
    name = $2,
    description = $3,
    color = $4,
    icon = $5,
    auto_assign_rules = $6,
    view_settings = $7
WHERE id = $1
RETURNING id, user_id, name, description, color, icon, auto_assign_rules, view_settings, show_on_dashboard, query_type, priority, is_system_collection, created_at
`

type UpdateCollectionParams struct {
	ID              pgtype.UUID `db:"id" json:"id"`
	Name            string      `db:"name" json:"name"`
	Description     pgtype.Text `db:"description" json:"description"`
	Color           pgtype.Text `db:"color" json:"color"`
	Icon            pgtype.Text `db:"icon" json:"icon"`
	AutoAssignRules []byte      `db:"auto_assign_rules" json:"auto_assign_rules"`
	ViewSettings    []byte      `db:"view_settings" json:"view_settings"`
}

// Update collection
func (q *Queries) UpdateCollection(ctx context.Context, arg UpdateCollectionParams) (Collections, error) {
	row := q.db.QueryRow(ctx, UpdateCollection,
		arg.ID,
		arg.Name,
		arg.Description,
		arg.Color,
		arg.Icon,
		arg.AutoAssignRules,
		arg.ViewSettings,
	)
	var i Collections
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.Name,
		&i.Description,
		&i.Color,
		&i.Icon,
		&i.AutoAssignRules,
		&i.ViewSettings,
		&i.ShowOnDashboard,
		&i.QueryType,
		&i.Priority,
		&i.IsSystemCollection,
		&i.CreatedAt,
	)
	return i, err
}

const UpdateDashboardPreferences = `-- name: UpdateDashboardPreferences :one
UPDATE user_dashboard_preferences
SET hidden_collections = $2,
    collection_order = $3,
    items_per_section = $4,
    updated_at = NOW()
WHERE user_id = $1 AND library_id = $5
RETURNING id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at
`

type UpdateDashboardPreferencesParams struct {
	UserID            pgtype.UUID `db:"user_id" json:"user_id"`
	HiddenCollections []string    `db:"hidden_collections" json:"hidden_collections"`
	CollectionOrder   []string    `db:"collection_order" json:"collection_order"`
	ItemsPerSection   pgtype.Int4 `db:"items_per_section" json:"items_per_section"`
	LibraryID         pgtype.UUID `db:"library_id" json:"library_id"`
}

func (q *Queries) UpdateDashboardPreferences(ctx context.Context, arg UpdateDashboardPreferencesParams) (UserDashboardPreferences, error) {
	row := q.db.QueryRow(ctx, UpdateDashboardPreferences,
		arg.UserID,
		arg.HiddenCollections,
		arg.CollectionOrder,
		arg.ItemsPerSection,
		arg.LibraryID,
	)
	var i UserDashboardPreferences
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.LibraryID,
		&i.HiddenCollections,
		&i.CollectionOrder,
		&i.ItemsPerSection,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdateDevice = `-- name: UpdateDevice :one
UPDATE devices
SET
    device_name = $2,
    sync_enabled = $3,
    auto_sync = $4,
    sync_frequency_minutes = $5,
    device_metadata = $6,
    updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`

type UpdateDeviceParams struct {
	ID                   pgtype.UUID `db:"id" json:"id"`
	DeviceName           string      `db:"device_name" json:"device_name"`
	SyncEnabled          pgtype.Bool `db:"sync_enabled" json:"sync_enabled"`
	AutoSync             pgtype.Bool `db:"auto_sync" json:"auto_sync"`
	SyncFrequencyMinutes pgtype.Int4 `db:"sync_frequency_minutes" json:"sync_frequency_minutes"`
	DeviceMetadata       []byte      `db:"device_metadata" json:"device_metadata"`
}

func (q *Queries) UpdateDevice(ctx context.Context, arg UpdateDeviceParams) (Devices, error) {
	row := q.db.QueryRow(ctx, UpdateDevice,
		arg.ID,
		arg.DeviceName,
		arg.SyncEnabled,
		arg.AutoSync,
		arg.SyncFrequencyMinutes,
		arg.DeviceMetadata,
	)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdateDeviceAuthToken = `-- name: UpdateDeviceAuthToken :one
UPDATE devices
SET
    auth_token = $2,
    updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`

type UpdateDeviceAuthTokenParams struct {
	ID        pgtype.UUID `db:"id" json:"id"`
	AuthToken string      `db:"auth_token" json:"auth_token"`
}

func (q *Queries) UpdateDeviceAuthToken(ctx context.Context, arg UpdateDeviceAuthTokenParams) (Devices, error) {
	row := q.db.QueryRow(ctx, UpdateDeviceAuthToken, arg.ID, arg.AuthToken)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdateDeviceCatalogAvailability = `-- name: UpdateDeviceCatalogAvailability :exec
UPDATE device_catalogs
SET available = $2
WHERE id = $1
`

type UpdateDeviceCatalogAvailabilityParams struct {
	ID        pgtype.UUID `db:"id" json:"id"`
	Available pgtype.Bool `db:"available" json:"available"`
}

// Update device catalog availability
func (q *Queries) UpdateDeviceCatalogAvailability(ctx context.Context, arg UpdateDeviceCatalogAvailabilityParams) error {
	_, err := q.db.Exec(ctx, UpdateDeviceCatalogAvailability, arg.ID, arg.Available)
	return err
}

const UpdateDeviceFileAlias = `-- name: UpdateDeviceFileAlias :one
UPDATE device_file_aliases
SET
    media_item_id = $2,
    file_sha256 = $3,
    confidence_score = $4,
    last_seen_at = NOW()
WHERE id = $1
RETURNING id, media_item_id, device_id, file_path, file_sha256, confidence_score, last_seen_at
`

type UpdateDeviceFileAliasParams struct {
	ID              pgtype.UUID   `db:"id" json:"id"`
	MediaItemID     pgtype.UUID   `db:"media_item_id" json:"media_item_id"`
	FileSha256      pgtype.Text   `db:"file_sha256" json:"file_sha256"`
	ConfidenceScore pgtype.Float8 `db:"confidence_score" json:"confidence_score"`
}

// Update device file alias
func (q *Queries) UpdateDeviceFileAlias(ctx context.Context, arg UpdateDeviceFileAliasParams) (DeviceFileAliases, error) {
	row := q.db.QueryRow(ctx, UpdateDeviceFileAlias,
		arg.ID,
		arg.MediaItemID,
		arg.FileSha256,
		arg.ConfidenceScore,
	)
	var i DeviceFileAliases
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.DeviceID,
		&i.FilePath,
		&i.FileSha256,
		&i.ConfidenceScore,
		&i.LastSeenAt,
	)
	return i, err
}

const UpdateDeviceLastSeen = `-- name: UpdateDeviceLastSeen :one
UPDATE devices
SET
    last_seen = NOW(),
    updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`

func (q *Queries) UpdateDeviceLastSeen(ctx context.Context, id pgtype.UUID) (Devices, error) {
	row := q.db.QueryRow(ctx, UpdateDeviceLastSeen, id)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdateDeviceLastSync = `-- name: UpdateDeviceLastSync :one
UPDATE devices
SET
    last_sync = NOW(),
    last_seen = NOW(),
    updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`

func (q *Queries) UpdateDeviceLastSync(ctx context.Context, id pgtype.UUID) (Devices, error) {
	row := q.db.QueryRow(ctx, UpdateDeviceLastSync, id)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdateDeviceShelfMapping = `-- name: UpdateDeviceShelfMapping :one
UPDATE device_shelf_mappings
SET
    device_shelf_name = $2,
    sync_direction = $3
WHERE id = $1
RETURNING id, collection_id, device_id, device_shelf_name, sync_direction, created_at
`

type UpdateDeviceShelfMappingParams struct {
	ID              pgtype.UUID `db:"id" json:"id"`
	DeviceShelfName pgtype.Text `db:"device_shelf_name" json:"device_shelf_name"`
	SyncDirection   pgtype.Text `db:"sync_direction" json:"sync_direction"`
}

// Update device shelf mapping
func (q *Queries) UpdateDeviceShelfMapping(ctx context.Context, arg UpdateDeviceShelfMappingParams) (DeviceShelfMappings, error) {
	row := q.db.QueryRow(ctx, UpdateDeviceShelfMapping, arg.ID, arg.DeviceShelfName, arg.SyncDirection)
	var i DeviceShelfMappings
	err := row.Scan(
		&i.ID,
		&i.CollectionID,
		&i.DeviceID,
		&i.DeviceShelfName,
		&i.SyncDirection,
		&i.CreatedAt,
	)
	return i, err
}

const UpdateDeviceSyncTimestamp = `-- name: UpdateDeviceSyncTimestamp :one
UPDATE devices
SET
    last_sync = NOW(),
    last_seen = NOW(),
    updated_at = NOW()
WHERE id = $1
RETURNING id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at
`

func (q *Queries) UpdateDeviceSyncTimestamp(ctx context.Context, id pgtype.UUID) (Devices, error) {
	row := q.db.QueryRow(ctx, UpdateDeviceSyncTimestamp, id)
	var i Devices
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.DeviceName,
		&i.DeviceType,
		&i.DeviceIdentifier,
		&i.AuthToken,
		&i.LastSync,
		&i.LastSeen,
		&i.SyncEnabled,
		&i.AutoSync,
		&i.SyncFrequencyMinutes,
		&i.DeviceMetadata,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdateEmail = `-- name: UpdateEmail :exec
UPDATE users SET email = $2, updated_at = NOW() WHERE id = $1
`

type UpdateEmailParams struct {
	ID    pgtype.UUID `db:"id" json:"id"`
	Email string      `db:"email" json:"email"`
}

func (q *Queries) UpdateEmail(ctx context.Context, arg UpdateEmailParams) error {
	_, err := q.db.Exec(ctx, UpdateEmail, arg.ID, arg.Email)
	return err
}

const UpdateKoboEntitlementRevision = `-- name: UpdateKoboEntitlementRevision :exec
UPDATE kobo_entitlements
SET revision_number = $3, updated_at = NOW()
WHERE device_id = $1 AND entitlement_id = $2
`

type UpdateKoboEntitlementRevisionParams struct {
	DeviceID       pgtype.UUID `db:"device_id" json:"device_id"`
	EntitlementID  string      `db:"entitlement_id" json:"entitlement_id"`
	RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
}

func (q *Queries) UpdateKoboEntitlementRevision(ctx context.Context, arg UpdateKoboEntitlementRevisionParams) error {
	_, err := q.db.Exec(ctx, UpdateKoboEntitlementRevision, arg.DeviceID, arg.EntitlementID, arg.RevisionNumber)
	return err
}

const UpdateKoboEntitlementStatus = `-- name: UpdateKoboEntitlementStatus :exec
UPDATE kobo_entitlements
SET book_status = $3, sync_status = 'synced', updated_at = NOW()
WHERE device_id = $1 AND entitlement_id = $2
`

type UpdateKoboEntitlementStatusParams struct {
	DeviceID      pgtype.UUID `db:"device_id" json:"device_id"`
	EntitlementID string      `db:"entitlement_id" json:"entitlement_id"`
	BookStatus    pgtype.Text `db:"book_status" json:"book_status"`
}

func (q *Queries) UpdateKoboEntitlementStatus(ctx context.Context, arg UpdateKoboEntitlementStatusParams) error {
	_, err := q.db.Exec(ctx, UpdateKoboEntitlementStatus, arg.DeviceID, arg.EntitlementID, arg.BookStatus)
	return err
}

const UpdateKoboShelfBookPosition = `-- name: UpdateKoboShelfBookPosition :exec
UPDATE kobo_shelves
SET shelf_position = $3, last_synced_at = NOW()
WHERE device_id = $1 AND media_item_id = $2
`

type UpdateKoboShelfBookPositionParams struct {
	DeviceID      pgtype.UUID `db:"device_id" json:"device_id"`
	MediaItemID   pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	ShelfPosition pgtype.Int4 `db:"shelf_position" json:"shelf_position"`
}

func (q *Queries) UpdateKoboShelfBookPosition(ctx context.Context, arg UpdateKoboShelfBookPositionParams) error {
	_, err := q.db.Exec(ctx, UpdateKoboShelfBookPosition, arg.DeviceID, arg.MediaItemID, arg.ShelfPosition)
	return err
}

const UpdateKoboShelfCollection = `-- name: UpdateKoboShelfCollection :one
UPDATE kobo_shelves
SET
    collection_id = $2,
    position_in_collection = $3,
    last_synced_at = NOW()
WHERE id = $1
RETURNING id, device_id, media_item_id, shelf_name, shelf_position, added_at, last_synced_at, collection_id, position_in_collection
`

type UpdateKoboShelfCollectionParams struct {
	ID                   pgtype.UUID `db:"id" json:"id"`
	CollectionID         pgtype.UUID `db:"collection_id" json:"collection_id"`
	PositionInCollection pgtype.Int4 `db:"position_in_collection" json:"position_in_collection"`
}

// Update Kobo shelves to support collections
func (q *Queries) UpdateKoboShelfCollection(ctx context.Context, arg UpdateKoboShelfCollectionParams) (KoboShelves, error) {
	row := q.db.QueryRow(ctx, UpdateKoboShelfCollection, arg.ID, arg.CollectionID, arg.PositionInCollection)
	var i KoboShelves
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.ShelfName,
		&i.ShelfPosition,
		&i.AddedAt,
		&i.LastSyncedAt,
		&i.CollectionID,
		&i.PositionInCollection,
	)
	return i, err
}

const UpdateLibrary = `-- name: UpdateLibrary :one
UPDATE libraries SET
    name = $2,
    description = $3,
    updated_at = NOW()
WHERE id = $1
RETURNING id, name, description, library_type_id, created_by_admin_id, created_at, updated_at
`

type UpdateLibraryParams struct {
	ID          pgtype.UUID `db:"id" json:"id"`
	Name        string      `db:"name" json:"name"`
	Description pgtype.Text `db:"description" json:"description"`
}

func (q *Queries) UpdateLibrary(ctx context.Context, arg UpdateLibraryParams) (Libraries, error) {
	row := q.db.QueryRow(ctx, UpdateLibrary, arg.ID, arg.Name, arg.Description)
	var i Libraries
	err := row.Scan(
		&i.ID,
		&i.Name,
		&i.Description,
		&i.LibraryTypeID,
		&i.CreatedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdateMediaHighlight = `-- name: UpdateMediaHighlight :one
UPDATE media_highlights SET
    selection_text = $2,
    start_position = $3,
    end_position = $4,
    color = $5,
    note_id = $6,
    updated_at = NOW()
WHERE id = $1
RETURNING id, media_item_id, user_id, selection_text, start_position, end_position, color, note_id, created_at, updated_at, percentage_start, percentage_end, character_start, character_end, epubcfi_start, epubcfi_end, chapter_reference, paragraph_start, paragraph_end, panel_number, device_sync_data
`

type UpdateMediaHighlightParams struct {
	ID            pgtype.UUID `db:"id" json:"id"`
	SelectionText string      `db:"selection_text" json:"selection_text"`
	StartPosition pgtype.Text `db:"start_position" json:"start_position"`
	EndPosition   pgtype.Text `db:"end_position" json:"end_position"`
	Color         pgtype.Text `db:"color" json:"color"`
	NoteID        pgtype.UUID `db:"note_id" json:"note_id"`
}

func (q *Queries) UpdateMediaHighlight(ctx context.Context, arg UpdateMediaHighlightParams) (MediaHighlights, error) {
	row := q.db.QueryRow(ctx, UpdateMediaHighlight,
		arg.ID,
		arg.SelectionText,
		arg.StartPosition,
		arg.EndPosition,
		arg.Color,
		arg.NoteID,
	)
	var i MediaHighlights
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.SelectionText,
		&i.StartPosition,
		&i.EndPosition,
		&i.Color,
		&i.NoteID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PercentageStart,
		&i.PercentageEnd,
		&i.CharacterStart,
		&i.CharacterEnd,
		&i.EpubcfiStart,
		&i.EpubcfiEnd,
		&i.ChapterReference,
		&i.ParagraphStart,
		&i.ParagraphEnd,
		&i.PanelNumber,
		&i.DeviceSyncData,
	)
	return i, err
}

const UpdateMediaItem = `-- name: UpdateMediaItem :one
UPDATE media_items SET
    title = $2,
    author = $3,
    isbn = $4,
    description = $5,
    cover_image_path = $6,
    series = $7,
    series_number = $8,
    tags = $9,
    tags_search = $10,
    asin = $11,
    date_published = $12,
    publisher = $13,
    contributors = $14,
    contributors_search = $15,
    language = $16,
    edition = $17,
    page_count = $18,
    genre = $19,
    copyright_year = $20,
    goodreads_id = $21,
    openlibrary_id = $22,
    google_books_id = $23,
    updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`

type UpdateMediaItemParams struct {
	ID                 pgtype.UUID `db:"id" json:"id"`
	Title              string      `db:"title" json:"title"`
	Author             pgtype.Text `db:"author" json:"author"`
	Isbn               pgtype.Text `db:"isbn" json:"isbn"`
	Description        pgtype.Text `db:"description" json:"description"`
	CoverImagePath     pgtype.Text `db:"cover_image_path" json:"cover_image_path"`
	Series             pgtype.Text `db:"series" json:"series"`
	SeriesNumber       pgtype.Int4 `db:"series_number" json:"series_number"`
	Tags               []string    `db:"tags" json:"tags"`
	TagsSearch         []string    `db:"tags_search" json:"tags_search"`
	Asin               pgtype.Text `db:"asin" json:"asin"`
	DatePublished      pgtype.Date `db:"date_published" json:"date_published"`
	Publisher          pgtype.Text `db:"publisher" json:"publisher"`
	Contributors       []string    `db:"contributors" json:"contributors"`
	ContributorsSearch []string    `db:"contributors_search" json:"contributors_search"`
	Language           pgtype.Text `db:"language" json:"language"`
	Edition            pgtype.Text `db:"edition" json:"edition"`
	PageCount          pgtype.Int4 `db:"page_count" json:"page_count"`
	Genre              pgtype.Text `db:"genre" json:"genre"`
	CopyrightYear      pgtype.Int4 `db:"copyright_year" json:"copyright_year"`
	GoodreadsID        pgtype.Text `db:"goodreads_id" json:"goodreads_id"`
	OpenlibraryID      pgtype.Text `db:"openlibrary_id" json:"openlibrary_id"`
	GoogleBooksID      pgtype.Text `db:"google_books_id" json:"google_books_id"`
}

func (q *Queries) UpdateMediaItem(ctx context.Context, arg UpdateMediaItemParams) (MediaItems, error) {
	row := q.db.QueryRow(ctx, UpdateMediaItem,
		arg.ID,
		arg.Title,
		arg.Author,
		arg.Isbn,
		arg.Description,
		arg.CoverImagePath,
		arg.Series,
		arg.SeriesNumber,
		arg.Tags,
		arg.TagsSearch,
		arg.Asin,
		arg.DatePublished,
		arg.Publisher,
		arg.Contributors,
		arg.ContributorsSearch,
		arg.Language,
		arg.Edition,
		arg.PageCount,
		arg.Genre,
		arg.CopyrightYear,
		arg.GoodreadsID,
		arg.OpenlibraryID,
		arg.GoogleBooksID,
	)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const UpdateMediaItemFormat = `-- name: UpdateMediaItemFormat :one
UPDATE media_item_formats
SET
    file_path = $2,
    file_sha256 = $3,
    file_size_bytes = $4,
    mime_type = $5
WHERE id = $1
RETURNING id, media_item_id, format_type, file_path, file_sha256, file_size_bytes, mime_type, created_at, converted_from_format_id
`

type UpdateMediaItemFormatParams struct {
	ID            pgtype.UUID `db:"id" json:"id"`
	FilePath      pgtype.Text `db:"file_path" json:"file_path"`
	FileSha256    pgtype.Text `db:"file_sha256" json:"file_sha256"`
	FileSizeBytes pgtype.Int8 `db:"file_size_bytes" json:"file_size_bytes"`
	MimeType      pgtype.Text `db:"mime_type" json:"mime_type"`
}

// Update media item format
func (q *Queries) UpdateMediaItemFormat(ctx context.Context, arg UpdateMediaItemFormatParams) (MediaItemFormats, error) {
	row := q.db.QueryRow(ctx, UpdateMediaItemFormat,
		arg.ID,
		arg.FilePath,
		arg.FileSha256,
		arg.FileSizeBytes,
		arg.MimeType,
	)
	var i MediaItemFormats
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.FormatType,
		&i.FilePath,
		&i.FileSha256,
		&i.FileSizeBytes,
		&i.MimeType,
		&i.CreatedAt,
		&i.ConvertedFromFormatID,
	)
	return i, err
}

const UpdateMediaItemFormatGroup = `-- name: UpdateMediaItemFormatGroup :exec

UPDATE media_items
SET
    format_group = $2,
    format_mimetype = $3,
    is_reflowable = $4,
    has_fixed_layout = $5,
    total_characters = $6,
    chapter_count = $7,
    updated_at = NOW()
WHERE id = $1
`

type UpdateMediaItemFormatGroupParams struct {
	ID              pgtype.UUID `db:"id" json:"id"`
	FormatGroup     string      `db:"format_group" json:"format_group"`
	FormatMimetype  pgtype.Text `db:"format_mimetype" json:"format_mimetype"`
	IsReflowable    pgtype.Bool `db:"is_reflowable" json:"is_reflowable"`
	HasFixedLayout  pgtype.Bool `db:"has_fixed_layout" json:"has_fixed_layout"`
	TotalCharacters pgtype.Int8 `db:"total_characters" json:"total_characters"`
	ChapterCount    pgtype.Int4 `db:"chapter_count" json:"chapter_count"`
}

// ============================================
// FORMAT DETECTION & PROGRESS
// ============================================
// Update media item format group information
func (q *Queries) UpdateMediaItemFormatGroup(ctx context.Context, arg UpdateMediaItemFormatGroupParams) error {
	_, err := q.db.Exec(ctx, UpdateMediaItemFormatGroup,
		arg.ID,
		arg.FormatGroup,
		arg.FormatMimetype,
		arg.IsReflowable,
		arg.HasFixedLayout,
		arg.TotalCharacters,
		arg.ChapterCount,
	)
	return err
}

const UpdateMediaItemIdentifiers = `-- name: UpdateMediaItemIdentifiers :one


UPDATE media_items
SET
    file_sha256 = $2,
    opf_identifier = $3,
    opf_uuid = $4,
    hash_confidence = $5,
    updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`

type UpdateMediaItemIdentifiersParams struct {
	ID             pgtype.UUID `db:"id" json:"id"`
	FileSha256     pgtype.Text `db:"file_sha256" json:"file_sha256"`
	OpfIdentifier  pgtype.Text `db:"opf_identifier" json:"opf_identifier"`
	OpfUuid        pgtype.Text `db:"opf_uuid" json:"opf_uuid"`
	HashConfidence pgtype.Text `db:"hash_confidence" json:"hash_confidence"`
}

// Media Items Admin Operations
// ============================================
// UNIVERSAL BOOK IDENTIFIERS
// ============================================
// Update media item with universal identifiers
func (q *Queries) UpdateMediaItemIdentifiers(ctx context.Context, arg UpdateMediaItemIdentifiersParams) (MediaItems, error) {
	row := q.db.QueryRow(ctx, UpdateMediaItemIdentifiers,
		arg.ID,
		arg.FileSha256,
		arg.OpfIdentifier,
		arg.OpfUuid,
		arg.HashConfidence,
	)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const UpdateMediaItemKoboMetadata = `-- name: UpdateMediaItemKoboMetadata :one
UPDATE media_items
SET entitlement_id = $2,
    kobo_content_id = $3,
    revision_number = COALESCE($4, revision_number) + 1,
    kobo_metadata = $5,
    updated_at = NOW()
WHERE id = $1
RETURNING id, library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, asin, date_published, publisher, contributors, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, updated_at, format_group, format_mimetype, is_reflowable, has_fixed_layout, total_characters, chapter_count, entitlement_id, revision_number, kobo_content_id, kobo_metadata, tags_search, contributors_search, file_sha256, opf_identifier, opf_uuid, hash_confidence
`

type UpdateMediaItemKoboMetadataParams struct {
	ID             pgtype.UUID `db:"id" json:"id"`
	EntitlementID  pgtype.Text `db:"entitlement_id" json:"entitlement_id"`
	KoboContentID  pgtype.Text `db:"kobo_content_id" json:"kobo_content_id"`
	RevisionNumber pgtype.Int4 `db:"revision_number" json:"revision_number"`
	KoboMetadata   []byte      `db:"kobo_metadata" json:"kobo_metadata"`
}

func (q *Queries) UpdateMediaItemKoboMetadata(ctx context.Context, arg UpdateMediaItemKoboMetadataParams) (MediaItems, error) {
	row := q.db.QueryRow(ctx, UpdateMediaItemKoboMetadata,
		arg.ID,
		arg.EntitlementID,
		arg.KoboContentID,
		arg.RevisionNumber,
		arg.KoboMetadata,
	)
	var i MediaItems
	err := row.Scan(
		&i.ID,
		&i.LibraryID,
		&i.Title,
		&i.Author,
		&i.Isbn,
		&i.Description,
		&i.FilePath,
		&i.FileSize,
		&i.MimeType,
		&i.CoverImagePath,
		&i.Series,
		&i.SeriesNumber,
		&i.Tags,
		&i.Asin,
		&i.DatePublished,
		&i.Publisher,
		&i.Contributors,
		&i.Language,
		&i.Edition,
		&i.PageCount,
		&i.Genre,
		&i.CopyrightYear,
		&i.GoodreadsID,
		&i.OpenlibraryID,
		&i.GoogleBooksID,
		&i.AddedByAdminID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.FormatGroup,
		&i.FormatMimetype,
		&i.IsReflowable,
		&i.HasFixedLayout,
		&i.TotalCharacters,
		&i.ChapterCount,
		&i.EntitlementID,
		&i.RevisionNumber,
		&i.KoboContentID,
		&i.KoboMetadata,
		&i.TagsSearch,
		&i.ContributorsSearch,
		&i.FileSha256,
		&i.OpfIdentifier,
		&i.OpfUuid,
		&i.HashConfidence,
	)
	return i, err
}

const UpdateMediaNote = `-- name: UpdateMediaNote :one
UPDATE media_notes SET
    content = $2,
    position = $3,
    updated_at = NOW()
WHERE id = $1
RETURNING id, media_item_id, user_id, content, position, created_at, updated_at, percentage_location, character_start, character_end, epubcfi_location, chapter_reference, paragraph_reference, device_sync_data
`

type UpdateMediaNoteParams struct {
	ID       pgtype.UUID `db:"id" json:"id"`
	Content  string      `db:"content" json:"content"`
	Position pgtype.Text `db:"position" json:"position"`
}

func (q *Queries) UpdateMediaNote(ctx context.Context, arg UpdateMediaNoteParams) (MediaNotes, error) {
	row := q.db.QueryRow(ctx, UpdateMediaNote, arg.ID, arg.Content, arg.Position)
	var i MediaNotes
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.Content,
		&i.Position,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.PercentageLocation,
		&i.CharacterStart,
		&i.CharacterEnd,
		&i.EpubcfiLocation,
		&i.ChapterReference,
		&i.ParagraphReference,
		&i.DeviceSyncData,
	)
	return i, err
}

const UpdateMediaRating = `-- name: UpdateMediaRating :one
UPDATE media_ratings SET
    rating = $3,
    updated_at = NOW()
WHERE media_item_id = $1 AND user_id = $2
RETURNING id, media_item_id, user_id, rating, created_at, updated_at
`

type UpdateMediaRatingParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
	Rating      int32       `db:"rating" json:"rating"`
}

func (q *Queries) UpdateMediaRating(ctx context.Context, arg UpdateMediaRatingParams) (MediaRatings, error) {
	row := q.db.QueryRow(ctx, UpdateMediaRating, arg.MediaItemID, arg.UserID, arg.Rating)
	var i MediaRatings
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.Rating,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdatePassword = `-- name: UpdatePassword :exec
UPDATE users SET password_hash = $2, updated_at = NOW() WHERE id = $1
`

type UpdatePasswordParams struct {
	ID           pgtype.UUID `db:"id" json:"id"`
	PasswordHash string      `db:"password_hash" json:"password_hash"`
}

func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error {
	_, err := q.db.Exec(ctx, UpdatePassword, arg.ID, arg.PasswordHash)
	return err
}

const UpdateReadingProgress = `-- name: UpdateReadingProgress :one
INSERT INTO reading_progress (media_item_id, user_id, current_page, total_pages, last_read_at)
VALUES ($1, $2, $3, $4, NOW())
ON CONFLICT (media_item_id, user_id)
DO UPDATE SET
    current_page = EXCLUDED.current_page,
    total_pages = EXCLUDED.total_pages,
    last_read_at = NOW()
RETURNING id, media_item_id, user_id, current_page, total_pages, last_read_at, percentage, character_offset, epubcfi, chapter, chapter_progress, viewport_x, viewport_y, zoom_level, scroll_position_x, scroll_position_y, panel_number, reading_mode, last_sync_device, last_sync_source, last_sync_timestamp, conflict_detected, conflict_resolved
`

type UpdateReadingProgressParams struct {
	MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
	UserID      pgtype.UUID `db:"user_id" json:"user_id"`
	CurrentPage pgtype.Int4 `db:"current_page" json:"current_page"`
	TotalPages  pgtype.Int4 `db:"total_pages" json:"total_pages"`
}

func (q *Queries) UpdateReadingProgress(ctx context.Context, arg UpdateReadingProgressParams) (ReadingProgress, error) {
	row := q.db.QueryRow(ctx, UpdateReadingProgress,
		arg.MediaItemID,
		arg.UserID,
		arg.CurrentPage,
		arg.TotalPages,
	)
	var i ReadingProgress
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.CurrentPage,
		&i.TotalPages,
		&i.LastReadAt,
		&i.Percentage,
		&i.CharacterOffset,
		&i.Epubcfi,
		&i.Chapter,
		&i.ChapterProgress,
		&i.ViewportX,
		&i.ViewportY,
		&i.ZoomLevel,
		&i.ScrollPositionX,
		&i.ScrollPositionY,
		&i.PanelNumber,
		&i.ReadingMode,
		&i.LastSyncDevice,
		&i.LastSyncSource,
		&i.LastSyncTimestamp,
		&i.ConflictDetected,
		&i.ConflictResolved,
	)
	return i, err
}

const UpdateSyncQueueItemStatus = `-- name: UpdateSyncQueueItemStatus :one
UPDATE sync_queue
SET
    status = $2,
    attempts = attempts + 1,
    error_message = $3,
    processed_at = CASE WHEN $2::varchar = 'completed' THEN NOW() ELSE NULL END
WHERE id = $1
RETURNING id, device_id, media_item_id, sync_type, sync_data, priority, attempts, max_attempts, status, error_message, created_at, processed_at
`

type UpdateSyncQueueItemStatusParams struct {
	ID           pgtype.UUID `db:"id" json:"id"`
	Status       pgtype.Text `db:"status" json:"status"`
	ErrorMessage pgtype.Text `db:"error_message" json:"error_message"`
}

func (q *Queries) UpdateSyncQueueItemStatus(ctx context.Context, arg UpdateSyncQueueItemStatusParams) (SyncQueue, error) {
	row := q.db.QueryRow(ctx, UpdateSyncQueueItemStatus, arg.ID, arg.Status, arg.ErrorMessage)
	var i SyncQueue
	err := row.Scan(
		&i.ID,
		&i.DeviceID,
		&i.MediaItemID,
		&i.SyncType,
		&i.SyncData,
		&i.Priority,
		&i.Attempts,
		&i.MaxAttempts,
		&i.Status,
		&i.ErrorMessage,
		&i.CreatedAt,
		&i.ProcessedAt,
	)
	return i, err
}

const UpdateSystemSetting = `-- name: UpdateSystemSetting :exec
UPDATE system_settings SET setting_value = $2, updated_at = NOW() WHERE setting_key = $1
`

type UpdateSystemSettingParams struct {
	SettingKey   string `db:"setting_key" json:"setting_key"`
	SettingValue string `db:"setting_value" json:"setting_value"`
}

func (q *Queries) UpdateSystemSetting(ctx context.Context, arg UpdateSystemSettingParams) error {
	_, err := q.db.Exec(ctx, UpdateSystemSetting, arg.SettingKey, arg.SettingValue)
	return err
}

const UpdateUniversalProgress = `-- name: UpdateUniversalProgress :one
INSERT INTO reading_progress (
    media_item_id,
    user_id,
    percentage,
    character_offset,
    epubcfi,
    chapter,
    chapter_progress,
    viewport_x,
    viewport_y,
    zoom_level,
    scroll_position_x,
    scroll_position_y,
    panel_number,
    reading_mode,
    last_sync_device,
    last_sync_source,
    last_sync_timestamp,
    current_page,
    total_pages,
    last_read_at
)
VALUES (
    $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, NOW(), $17, $18, NOW()
)
ON CONFLICT (media_item_id, user_id)
DO UPDATE SET
    percentage = EXCLUDED.percentage,
    character_offset = EXCLUDED.character_offset,
    epubcfi = EXCLUDED.epubcfi,
    chapter = EXCLUDED.chapter,
    chapter_progress = EXCLUDED.chapter_progress,
    viewport_x = EXCLUDED.viewport_x,
    viewport_y = EXCLUDED.viewport_y,
    zoom_level = EXCLUDED.zoom_level,
    scroll_position_x = EXCLUDED.scroll_position_x,
    scroll_position_y = EXCLUDED.scroll_position_y,
    panel_number = EXCLUDED.panel_number,
    reading_mode = EXCLUDED.reading_mode,
    last_sync_device = EXCLUDED.last_sync_device,
    last_sync_source = EXCLUDED.last_sync_source,
    last_sync_timestamp = EXCLUDED.last_sync_timestamp,
    current_page = EXCLUDED.current_page,
    total_pages = EXCLUDED.total_pages,
    last_read_at = NOW()
RETURNING id, media_item_id, user_id, current_page, total_pages, last_read_at, percentage, character_offset, epubcfi, chapter, chapter_progress, viewport_x, viewport_y, zoom_level, scroll_position_x, scroll_position_y, panel_number, reading_mode, last_sync_device, last_sync_source, last_sync_timestamp, conflict_detected, conflict_resolved
`

type UpdateUniversalProgressParams struct {
	MediaItemID     pgtype.UUID   `db:"media_item_id" json:"media_item_id"`
	UserID          pgtype.UUID   `db:"user_id" json:"user_id"`
	Percentage      pgtype.Float8 `db:"percentage" json:"percentage"`
	CharacterOffset pgtype.Int8   `db:"character_offset" json:"character_offset"`
	Epubcfi         pgtype.Text   `db:"epubcfi" json:"epubcfi"`
	Chapter         pgtype.Int4   `db:"chapter" json:"chapter"`
	ChapterProgress pgtype.Float8 `db:"chapter_progress" json:"chapter_progress"`
	ViewportX       pgtype.Float8 `db:"viewport_x" json:"viewport_x"`
	ViewportY       pgtype.Float8 `db:"viewport_y" json:"viewport_y"`
	ZoomLevel       pgtype.Float8 `db:"zoom_level" json:"zoom_level"`
	ScrollPositionX pgtype.Float8 `db:"scroll_position_x" json:"scroll_position_x"`
	ScrollPositionY pgtype.Float8 `db:"scroll_position_y" json:"scroll_position_y"`
	PanelNumber     pgtype.Int4   `db:"panel_number" json:"panel_number"`
	ReadingMode     pgtype.Text   `db:"reading_mode" json:"reading_mode"`
	LastSyncDevice  pgtype.Text   `db:"last_sync_device" json:"last_sync_device"`
	LastSyncSource  pgtype.Text   `db:"last_sync_source" json:"last_sync_source"`
	CurrentPage     pgtype.Int4   `db:"current_page" json:"current_page"`
	TotalPages      pgtype.Int4   `db:"total_pages" json:"total_pages"`
}

// Update universal progress
func (q *Queries) UpdateUniversalProgress(ctx context.Context, arg UpdateUniversalProgressParams) (ReadingProgress, error) {
	row := q.db.QueryRow(ctx, UpdateUniversalProgress,
		arg.MediaItemID,
		arg.UserID,
		arg.Percentage,
		arg.CharacterOffset,
		arg.Epubcfi,
		arg.Chapter,
		arg.ChapterProgress,
		arg.ViewportX,
		arg.ViewportY,
		arg.ZoomLevel,
		arg.ScrollPositionX,
		arg.ScrollPositionY,
		arg.PanelNumber,
		arg.ReadingMode,
		arg.LastSyncDevice,
		arg.LastSyncSource,
		arg.CurrentPage,
		arg.TotalPages,
	)
	var i ReadingProgress
	err := row.Scan(
		&i.ID,
		&i.MediaItemID,
		&i.UserID,
		&i.CurrentPage,
		&i.TotalPages,
		&i.LastReadAt,
		&i.Percentage,
		&i.CharacterOffset,
		&i.Epubcfi,
		&i.Chapter,
		&i.ChapterProgress,
		&i.ViewportX,
		&i.ViewportY,
		&i.ZoomLevel,
		&i.ScrollPositionX,
		&i.ScrollPositionY,
		&i.PanelNumber,
		&i.ReadingMode,
		&i.LastSyncDevice,
		&i.LastSyncSource,
		&i.LastSyncTimestamp,
		&i.ConflictDetected,
		&i.ConflictResolved,
	)
	return i, err
}

const UpdateUserMaxDevices = `-- name: UpdateUserMaxDevices :one
UPDATE users SET max_devices = $2, updated_at = NOW() WHERE id = $1
RETURNING id, email, username, password_hash, first_name, last_name, role, theme, max_devices, created_at, updated_at
`

type UpdateUserMaxDevicesParams struct {
	ID         pgtype.UUID `db:"id" json:"id"`
	MaxDevices pgtype.Int4 `db:"max_devices" json:"max_devices"`
}

func (q *Queries) UpdateUserMaxDevices(ctx context.Context, arg UpdateUserMaxDevicesParams) (Users, error) {
	row := q.db.QueryRow(ctx, UpdateUserMaxDevices, arg.ID, arg.MaxDevices)
	var i Users
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.Username,
		&i.PasswordHash,
		&i.FirstName,
		&i.LastName,
		&i.Role,
		&i.Theme,
		&i.MaxDevices,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}

const UpdateUserProfile = `-- name: UpdateUserProfile :exec
UPDATE users SET first_name = $2, last_name = $3, updated_at = NOW() WHERE id = $1
`

type UpdateUserProfileParams struct {
	ID        pgtype.UUID `db:"id" json:"id"`
	FirstName pgtype.Text `db:"first_name" json:"first_name"`
	LastName  pgtype.Text `db:"last_name" json:"last_name"`
}

func (q *Queries) UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) error {
	_, err := q.db.Exec(ctx, UpdateUserProfile, arg.ID, arg.FirstName, arg.LastName)
	return err
}

const UpdateUserRole = `-- name: UpdateUserRole :one
UPDATE users SET role = $2, updated_at = NOW() WHERE id = $1
RETURNING id, email, username, role
`

type UpdateUserRoleParams struct {
	ID   pgtype.UUID `db:"id" json:"id"`
	Role string      `db:"role" json:"role"`
}

type UpdateUserRoleRow struct {
	ID       pgtype.UUID `db:"id" json:"id"`
	Email    string      `db:"email" json:"email"`
	Username string      `db:"username" json:"username"`
	Role     string      `db:"role" json:"role"`
}

func (q *Queries) UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UpdateUserRoleRow, error) {
	row := q.db.QueryRow(ctx, UpdateUserRole, arg.ID, arg.Role)
	var i UpdateUserRoleRow
	err := row.Scan(
		&i.ID,
		&i.Email,
		&i.Username,
		&i.Role,
	)
	return i, err
}

const UpdateUserTheme = `-- name: UpdateUserTheme :exec
UPDATE users SET theme = $2, updated_at = NOW() WHERE id = $1
`

type UpdateUserThemeParams struct {
	ID    pgtype.UUID `db:"id" json:"id"`
	Theme pgtype.Text `db:"theme" json:"theme"`
}

func (q *Queries) UpdateUserTheme(ctx context.Context, arg UpdateUserThemeParams) error {
	_, err := q.db.Exec(ctx, UpdateUserTheme, arg.ID, arg.Theme)
	return err
}

const UpdateUsername = `-- name: UpdateUsername :exec
UPDATE users SET username = $2, updated_at = NOW() WHERE id = $1
`

type UpdateUsernameParams struct {
	ID       pgtype.UUID `db:"id" json:"id"`
	Username string      `db:"username" json:"username"`
}

func (q *Queries) UpdateUsername(ctx context.Context, arg UpdateUsernameParams) error {
	_, err := q.db.Exec(ctx, UpdateUsername, arg.ID, arg.Username)
	return err
}

const UpsertDashboardPreferences = `-- name: UpsertDashboardPreferences :one
INSERT INTO user_dashboard_preferences (user_id, library_id, hidden_collections, collection_order, items_per_section)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id, library_id)
DO UPDATE SET
    hidden_collections = EXCLUDED.hidden_collections,
    collection_order = EXCLUDED.collection_order,
    items_per_section = EXCLUDED.items_per_section,
    updated_at = NOW()
RETURNING id, user_id, library_id, hidden_collections, collection_order, items_per_section, created_at, updated_at
`

type UpsertDashboardPreferencesParams struct {
	UserID            pgtype.UUID `db:"user_id" json:"user_id"`
	LibraryID         pgtype.UUID `db:"library_id" json:"library_id"`
	HiddenCollections []string    `db:"hidden_collections" json:"hidden_collections"`
	CollectionOrder   []string    `db:"collection_order" json:"collection_order"`
	ItemsPerSection   pgtype.Int4 `db:"items_per_section" json:"items_per_section"`
}

func (q *Queries) UpsertDashboardPreferences(ctx context.Context, arg UpsertDashboardPreferencesParams) (UserDashboardPreferences, error) {
	row := q.db.QueryRow(ctx, UpsertDashboardPreferences,
		arg.UserID,
		arg.LibraryID,
		arg.HiddenCollections,
		arg.CollectionOrder,
		arg.ItemsPerSection,
	)
	var i UserDashboardPreferences
	err := row.Scan(
		&i.ID,
		&i.UserID,
		&i.LibraryID,
		&i.HiddenCollections,
		&i.CollectionOrder,
		&i.ItemsPerSection,
		&i.CreatedAt,
		&i.UpdatedAt,
	)
	return i, err
}
