"""Pre-built SQL query constants for the corpus database."""

from __future__ import annotations

# -- File queries -------------------------------------------------------------

FILE_BY_PATH = "SELECT id, file_mtime FROM files WHERE path = ?"

INSERT_FILE = """\
INSERT INTO files (path, name, stem, author, date, file_mtime, segment_count)
VALUES (?, ?, ?, ?, ?, ?, ?)
"""

DELETE_FILE = "DELETE FROM files WHERE path = ?"

# -- Media refs ---------------------------------------------------------------

INSERT_MEDIA_REF = """\
INSERT INTO media_refs (file_id, media_url, mime_type, relative_url)
VALUES (?, ?, ?, ?)
"""

# -- Tiers --------------------------------------------------------------------

INSERT_TIER = """\
INSERT INTO tiers (file_id, tier_id, linguistic_type, participant, annotator, parent_ref)
VALUES (?, ?, ?, ?, ?, ?)
"""

TIER_ROWID = "SELECT id FROM tiers WHERE file_id = ? AND tier_id = ?"

# -- Segments -----------------------------------------------------------------

INSERT_SEGMENT = """\
INSERT INTO segments (file_id, tier_rowid, annotation_id, start_ms, end_ms, label, confidence, source)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
"""

# -- Gloss queries ------------------------------------------------------------

FIND_GLOSS = """\
SELECT s.label, s.start_ms, s.end_ms, s.duration_ms,
       s.annotation_id, s.confidence, s.source,
       t.tier_id, t.participant,
       f.path, f.name, f.stem
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
JOIN files f ON s.file_id = f.id
WHERE s.label_lower = lower(?)
ORDER BY f.name, s.start_ms
"""

FIND_GLOSS_BY_SIGNER = """\
SELECT s.label, s.start_ms, s.end_ms, s.duration_ms,
       s.annotation_id, s.confidence, s.source,
       t.tier_id, t.participant,
       f.path, f.name, f.stem
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
JOIN files f ON s.file_id = f.id
WHERE s.label_lower = lower(?) AND t.participant = ?
ORDER BY f.name, s.start_ms
"""

GLOSS_DURATION_STATS = """\
SELECT count(*) AS cnt,
       avg(s.duration_ms) AS mean_ms,
       min(s.duration_ms) AS min_ms,
       max(s.duration_ms) AS max_ms
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
WHERE s.label_lower = lower(?)
"""

GLOSS_DURATION_STATS_BY_SIGNER = """\
SELECT count(*) AS cnt,
       avg(s.duration_ms) AS mean_ms,
       min(s.duration_ms) AS min_ms,
       max(s.duration_ms) AS max_ms
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
WHERE s.label_lower = lower(?) AND t.participant = ?
"""

GLOSS_DURATIONS_ALL = """\
SELECT s.duration_ms
FROM segments s
WHERE s.label_lower = lower(?)
ORDER BY s.duration_ms
"""

GLOSS_DURATIONS_BY_SIGNER = """\
SELECT s.duration_ms
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
WHERE s.label_lower = lower(?) AND t.participant = ?
ORDER BY s.duration_ms
"""

COMPARE_GLOSS_BY_SIGNER = """\
SELECT t.participant,
       count(*) AS cnt,
       avg(s.duration_ms) AS mean_ms,
       min(s.duration_ms) AS min_ms,
       max(s.duration_ms) AS max_ms
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
WHERE s.label_lower = lower(?) AND t.participant != ''
GROUP BY t.participant
ORDER BY cnt DESC
"""

# -- Top glosses --------------------------------------------------------------

TOP_GLOSSES = """\
SELECT s.label_lower AS gloss, count(*) AS freq
FROM segments s
WHERE s.label IS NOT NULL AND s.label != ''
GROUP BY s.label_lower
ORDER BY freq DESC
LIMIT ?
"""

# -- FTS search ---------------------------------------------------------------

FTS_SEARCH = """\
SELECT s.label, s.start_ms, s.end_ms, s.duration_ms,
       s.annotation_id, s.source,
       t.tier_id, t.participant,
       f.path, f.name
FROM segments_fts fts
JOIN segments s ON fts.rowid = s.id
JOIN tiers t ON s.tier_rowid = t.id
JOIN files f ON s.file_id = f.id
WHERE segments_fts MATCH ?
ORDER BY rank
LIMIT ?
"""

# -- Corpus summary -----------------------------------------------------------

CORPUS_SUMMARY = """\
SELECT
    (SELECT count(*) FROM files) AS total_files,
    (SELECT count(*) FROM segments) AS total_segments,
    (SELECT count(DISTINCT label_lower) FROM segments
     WHERE label IS NOT NULL AND label != '') AS vocabulary_size,
    (SELECT count(DISTINCT t.participant) FROM tiers t
     WHERE t.participant != '') AS signer_count,
    (SELECT count(*) FROM tiers) AS total_tiers
"""

DB_STATUS = """\
SELECT
    (SELECT count(*) FROM files) AS file_count,
    (SELECT count(*) FROM segments) AS segment_count,
    (SELECT value FROM meta WHERE key = 'last_updated') AS last_updated
"""

# -- Concordance (KWIC) ------------------------------------------------------

CONCORDANCE_SEGMENTS_BY_FILE = """\
SELECT s.id, s.label, s.start_ms, s.end_ms,
       t.tier_id, f.path, f.name
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
JOIN files f ON s.file_id = f.id
WHERE s.file_id = ?
ORDER BY t.tier_id, s.start_ms
"""

FILES_WITH_GLOSS = """\
SELECT DISTINCT f.id
FROM segments s
JOIN files f ON s.file_id = f.id
WHERE s.label_lower = lower(?)
"""

# -- N-gram -------------------------------------------------------------------

SEGMENTS_BY_FILE_TIER = """\
SELECT s.label
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
WHERE s.file_id = ? AND s.label IS NOT NULL AND s.label != ''
ORDER BY t.tier_id, s.start_ms
"""

ALL_FILE_IDS = "SELECT id FROM files"

# -- Co-occurrence ------------------------------------------------------------

SEGMENTS_FOR_COOCCURRENCE = """\
SELECT s.label
FROM segments s
WHERE s.file_id = ? AND s.label IS NOT NULL AND s.label != ''
ORDER BY s.start_ms
"""

# -- Vocabulary frequencies ---------------------------------------------------

VOCABULARY_FREQUENCIES = """\
SELECT s.label_lower AS gloss, count(*) AS freq
FROM segments s
WHERE s.label IS NOT NULL AND s.label != ''
GROUP BY s.label_lower
ORDER BY freq DESC
LIMIT ?
"""

# -- All gloss durations (for duration analysis) ------------------------------

ALL_GLOSS_DURATIONS = """\
SELECT s.label_lower AS gloss, s.duration_ms
FROM segments s
WHERE s.label IS NOT NULL AND s.label != '' AND s.duration_ms > 0
ORDER BY s.label_lower
"""

# -- Dashboard / frequency distribution --------------------------------------

FREQUENCY_DISTRIBUTION = """\
SELECT s.label_lower AS gloss, count(*) AS freq
FROM segments s
WHERE s.label IS NOT NULL AND s.label != ''
GROUP BY s.label_lower
ORDER BY freq DESC
"""

DURATION_HISTOGRAM = """\
SELECT s.duration_ms
FROM segments s
WHERE s.label IS NOT NULL AND s.label != '' AND s.duration_ms > 0
"""

# -- Lexical richness ---------------------------------------------------------

ALL_LABELS_ORDERED = """\
SELECT s.label_lower AS label
FROM segments s
WHERE s.label IS NOT NULL AND s.label != ''
ORDER BY s.file_id, s.start_ms
"""

LABELS_BY_SIGNER = """\
SELECT t.participant, s.label_lower AS label
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
WHERE s.label IS NOT NULL AND s.label != '' AND t.participant != ''
ORDER BY t.participant, s.file_id, s.start_ms
"""

# -- Transitions (bigrams) ---------------------------------------------------

LABELS_BY_FILE_ORDERED = """\
SELECT s.file_id, s.label_lower AS label
FROM segments s
WHERE s.label IS NOT NULL AND s.label != ''
ORDER BY s.file_id, s.start_ms
"""

# -- Fluency / temporal analysis ---------------------------------------------

SEGMENTS_PER_FILE_WITH_TIMING = """\
SELECT s.file_id, f.name, f.stem,
       s.start_ms, s.end_ms, s.duration_ms, s.label
FROM segments s
JOIN files f ON s.file_id = f.id
WHERE s.label IS NOT NULL AND s.label != '' AND s.duration_ms > 0
ORDER BY s.file_id, s.start_ms
"""

SEGMENTS_WITH_SIGNER = """\
SELECT s.file_id, f.name, f.stem, t.participant,
       s.start_ms, s.end_ms, s.duration_ms, s.label
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
JOIN files f ON s.file_id = f.id
WHERE s.label IS NOT NULL AND s.label != '' AND s.duration_ms > 0
ORDER BY t.participant, s.file_id, s.start_ms
"""

# -- File list ---------------------------------------------------------------

FILE_LIST = """\
SELECT f.id, f.path, f.name, f.stem,
       count(s.id) AS segment_count
FROM files f
LEFT JOIN segments s ON s.file_id = f.id
GROUP BY f.id
ORDER BY f.name
"""

# -- Path metadata extraction -------------------------------------------------

FILE_PATHS_WITH_IDS = "SELECT id, path FROM files ORDER BY path"

UPDATE_TIER_PARTICIPANT_EMPTY = """\
UPDATE tiers SET participant = ?
WHERE file_id = ? AND (participant IS NULL OR participant = '')
"""

UPDATE_TIER_PARTICIPANT_ALL = "UPDATE tiers SET participant = ? WHERE file_id = ?"

FILE_MAX_END_MS = """\
SELECT COALESCE(MAX(s.end_ms), 0) AS max_end_ms
FROM segments s WHERE s.file_id = ?
"""

SIGNERS_PER_FILE = """\
SELECT f.path, GROUP_CONCAT(DISTINCT t.participant) AS signers
FROM files f
JOIN tiers t ON t.file_id = f.id
WHERE t.participant IS NOT NULL AND t.participant != ''
GROUP BY f.id
ORDER BY f.path
"""

# -- File metadata --------------------------------------------------------

INSERT_FILE_METADATA = """\
INSERT OR REPLACE INTO file_metadata (file_id, key, value, source)
VALUES (?, ?, ?, ?)
"""

LIST_METADATA_KEYS = """\
SELECT key, COUNT(DISTINCT value) AS unique_values, COUNT(*) AS file_count,
       GROUP_CONCAT(DISTINCT source) AS sources
FROM file_metadata
GROUP BY key
ORDER BY key
"""

METADATA_VALUES_FOR_KEY = """\
SELECT value, COUNT(*) AS file_count
FROM file_metadata WHERE key = ?
GROUP BY value ORDER BY file_count DESC
"""

# -- Tier roles -----------------------------------------------------------

LIST_UNIQUE_TIER_IDS = """\
SELECT t.tier_id, t.linguistic_type, COUNT(s.id) AS segment_count,
       COUNT(DISTINCT t.file_id) AS file_count,
       COALESCE(tr.role, 'other') AS role,
       CASE WHEN tr.role IS NOT NULL THEN 1 ELSE 0 END AS is_explicit
FROM tiers t
LEFT JOIN tier_roles tr ON t.tier_id = tr.tier_id_pattern
LEFT JOIN segments s ON s.tier_rowid = t.id
GROUP BY t.tier_id
ORDER BY segment_count DESC
"""

SET_TIER_ROLE = """\
INSERT OR REPLACE INTO tier_roles (tier_id_pattern, role)
VALUES (?, ?)
"""

GET_TIER_ROLES = "SELECT tier_id_pattern, role FROM tier_roles"

DELETE_TIER_ROLE = "DELETE FROM tier_roles WHERE tier_id_pattern = ?"

DELETE_ALL_TIER_ROLES = "DELETE FROM tier_roles"

# -- Universal search --------------------------------------------------------

SEARCH_FILES = """\
SELECT f.id, f.path, f.name, f.stem,
       (SELECT COUNT(*) FROM segments s WHERE s.file_id = f.id) AS segment_count,
       (SELECT GROUP_CONCAT(DISTINCT t.participant)
        FROM tiers t WHERE t.file_id = f.id
        AND t.participant IS NOT NULL AND t.participant != '') AS signers
FROM files f
WHERE f.stem LIKE ? OR f.name LIKE ? OR f.path LIKE ?
ORDER BY f.name LIMIT ?
"""

SEARCH_SIGNERS = """\
SELECT t.participant,
       COUNT(DISTINCT t.file_id) AS file_count,
       COUNT(s.id) AS segment_count
FROM tiers t
LEFT JOIN segments s ON s.tier_rowid = t.id
WHERE t.participant LIKE ?
  AND t.participant IS NOT NULL AND t.participant != ''
GROUP BY t.participant
ORDER BY segment_count DESC LIMIT ?
"""

SEARCH_METADATA = """\
SELECT fm.key, fm.value,
       COUNT(DISTINCT fm.file_id) AS file_count,
       fm.source
FROM file_metadata fm
WHERE fm.value LIKE ?
GROUP BY fm.key, fm.value
ORDER BY file_count DESC LIMIT ?
"""

# -- Group comparison (by signer / participant) --------------------------------

GROUP_BY_PARTICIPANT = """\
SELECT t.participant AS group_value,
       COUNT(DISTINCT s.label_lower) AS vocabulary_size,
       COUNT(s.id) AS total_tokens,
       AVG(s.duration_ms) AS avg_duration_ms,
       COUNT(DISTINCT s.file_id) AS file_count
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
WHERE s.label IS NOT NULL AND s.label != '' AND t.participant != ''
GROUP BY t.participant
ORDER BY total_tokens DESC
"""

GROUP_BY_METADATA = """\
SELECT fm.value AS group_value,
       COUNT(DISTINCT s.label_lower) AS vocabulary_size,
       COUNT(s.id) AS total_tokens,
       AVG(s.duration_ms) AS avg_duration_ms,
       COUNT(DISTINCT s.file_id) AS file_count
FROM segments s
JOIN files f ON s.file_id = f.id
JOIN file_metadata fm ON fm.file_id = f.id AND fm.key = ?
WHERE s.label IS NOT NULL AND s.label != ''
GROUP BY fm.value
ORDER BY total_tokens DESC
"""

# -- Top glosses per group (signer or metadata) --------------------------------

TOP_GLOSSES_BY_PARTICIPANT = """\
SELECT t.participant AS group_value, s.label_lower AS gloss, COUNT(*) AS freq
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
WHERE s.label IS NOT NULL AND s.label != '' AND t.participant = ?
GROUP BY s.label_lower
ORDER BY freq DESC
LIMIT ?
"""

TOP_GLOSSES_BY_METADATA = """\
SELECT s.label_lower AS gloss, COUNT(*) AS freq
FROM segments s
JOIN files f ON s.file_id = f.id
JOIN file_metadata fm ON fm.file_id = f.id AND fm.key = ? AND fm.value = ?
WHERE s.label IS NOT NULL AND s.label != ''
GROUP BY s.label_lower
ORDER BY freq DESC
LIMIT ?
"""

# -- Hand comparison (left vs right from tier roles) ---------------------------

HAND_VOCAB_BY_ROLE = """\
SELECT s.label_lower AS gloss, COUNT(*) AS freq
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
JOIN tier_roles tr ON t.tier_id = tr.tier_id_pattern
WHERE tr.role = ? AND s.label IS NOT NULL AND s.label != ''
GROUP BY s.label_lower
ORDER BY freq DESC
"""

HAND_STATS_BY_ROLE = """\
SELECT COUNT(s.id) AS total_tokens,
       COUNT(DISTINCT s.label_lower) AS vocabulary_size,
       AVG(s.duration_ms) AS avg_duration_ms,
       COUNT(DISTINCT s.file_id) AS file_count
FROM segments s
JOIN tiers t ON s.tier_rowid = t.id
JOIN tier_roles tr ON t.tier_id = tr.tier_id_pattern
WHERE tr.role = ? AND s.label IS NOT NULL AND s.label != ''
"""

SIMULTANEOUS_SIGNS = """\
SELECT lh.label_lower AS left_gloss, rh.label_lower AS right_gloss,
       COUNT(*) AS freq
FROM segments lh
JOIN tiers lt ON lh.tier_rowid = lt.id
JOIN tier_roles ltr ON lt.tier_id = ltr.tier_id_pattern
JOIN segments rh ON rh.file_id = lh.file_id
JOIN tiers rt ON rh.tier_rowid = rt.id
JOIN tier_roles rtr ON rt.tier_id = rtr.tier_id_pattern
WHERE ltr.role = 'left_hand' AND rtr.role = 'right_hand'
  AND lh.label IS NOT NULL AND lh.label != ''
  AND rh.label IS NOT NULL AND rh.label != ''
  AND lh.start_ms < rh.end_ms AND rh.start_ms < lh.end_ms
GROUP BY lh.label_lower, rh.label_lower
ORDER BY freq DESC
LIMIT ?
"""
