-- 1) Vidéos manuelles (source unique, simple)
DROP VIEW IF EXISTS manual_playlists_videos;
CREATE VIEW manual_playlists_videos AS
SELECT
  p.id         AS playlist_id,
  p.name       AS playlist_name,
  'manual'     AS playlist_type,
  vp.video_file_name
FROM playlists p
JOIN video_playlists vp ON p.id = vp.playlist_id
WHERE p.type = 'manual';

-- 2) Vidéos dynamiques : tout sauf include_playlists / exclude_playlists
--    (ceci applique labels, date_after/date_before/date_delta_days, difficulty, day_of_week, address_keyword)
DROP VIEW IF EXISTS dynamic_playlist_videos_base;
CREATE VIEW dynamic_playlist_videos_base AS
SELECT DISTINCT
  p.id            AS playlist_id,
  p.name          AS playlist_name,
  'dynamic'       AS playlist_type,
  v.file_name     AS video_file_name
FROM playlists p
JOIN videos v
WHERE p.type = 'dynamic'

  /* --- include_labels (AND/OR) --- */
  AND (
    json_array_length(json_extract(p.rules_json, '$.include_labels')) = 0
    OR (
      json_extract(p.rules_json, '$.label_logic') = 'OR'
      AND EXISTS (
        SELECT 1 FROM json_each(json_extract(p.rules_json, '$.include_labels')) jl
        JOIN labels l ON l.name = jl.value
        JOIN video_labels vl ON vl.label_id = l.id AND vl.video_file_name = v.file_name
      )
    )
    OR (
      json_extract(p.rules_json, '$.label_logic') = 'AND'
      AND NOT EXISTS (
        -- il existe un label requis qui n'est pas présent pour la video
        SELECT 1
        FROM json_each(json_extract(p.rules_json, '$.include_labels')) jl
        WHERE jl.value NOT IN (
          SELECT l2.name
          FROM labels l2
          JOIN video_labels vl2 ON l2.id = vl2.label_id
          WHERE vl2.video_file_name = v.file_name
        )
      )
    )
  )

  /* --- exclude_labels --- */
  AND NOT EXISTS (
    SELECT 1 FROM json_each(json_extract(p.rules_json, '$.exclude_labels')) je
    JOIN labels lx ON lx.name = je.value
    JOIN video_labels vlx ON vlx.label_id = lx.id AND vlx.video_file_name = v.file_name
  )

  /* --- date_after / date_delta_days / date_before --- */
  AND (
    json_extract(p.rules_json, '$.date_after') IS NULL
    OR v.record_datetime >= json_extract(p.rules_json, '$.date_after')
    OR (
      json_extract(p.rules_json, '$.date_delta_days') IS NOT NULL
      AND v.record_datetime >= date('now', (json_extract(p.rules_json, '$.date_delta_days') || ' days'))
    )
  )
  AND (
    json_extract(p.rules_json, '$.date_before') IS NULL
    OR v.record_datetime <= json_extract(p.rules_json, '$.date_before')
  )

  /* --- difficulty, day_of_week, address_keyword --- */
  AND (
    json_extract(p.rules_json, '$.difficulty') IS NULL
    OR v.difficulty_level = json_extract(p.rules_json, '$.difficulty')
  )
  AND (
    json_extract(p.rules_json, '$.day_of_week') IS NULL
    OR v.day_of_week = json_extract(p.rules_json, '$.day_of_week')
  )
  AND (
    json_extract(p.rules_json, '$.address_keyword') IS NULL
    OR (
      v.address NOT LIKE '%unknown%'
      AND v.address LIKE '%' || json_extract(p.rules_json, '$.address_keyword') || '%'
    )
  );


-- 3) Mapping direct parent -> child playlist ids (extrait JSON include_playlists)
DROP VIEW IF EXISTS playlist_direct_includes;
CREATE VIEW playlist_direct_includes AS
SELECT
  p.id AS parent_playlist_id,
  CAST(inc.value AS INTEGER) AS child_playlist_id
FROM playlists p
JOIN json_each(json_extract(p.rules_json, '$.include_playlists')) inc
  ON json_type(inc.value) IN ('integer', 'text')
WHERE json_array_length(json_extract(p.rules_json, '$.include_playlists')) > 0;


-- 4) Fermeture transitive des inclusions : parent -> descendant child
DROP VIEW IF EXISTS playlist_includes_recursive;
CREATE VIEW playlist_includes_recursive AS
WITH RECURSIVE rec(parent_playlist_id, child_playlist_id) AS (
  -- base : les inclusions directes
  SELECT parent_playlist_id, child_playlist_id FROM playlist_direct_includes

  UNION ALL

  -- récursion : si A inclut B et B inclut C, alors A inclut C
  SELECT d.parent_playlist_id, di.child_playlist_id
  FROM playlist_direct_includes d
  JOIN rec di ON di.parent_playlist_id = d.child_playlist_id
)
SELECT DISTINCT parent_playlist_id AS parent_id, child_playlist_id AS child_id FROM rec;


-- 5) De même pour exclusions directes et récursives
DROP VIEW IF EXISTS playlist_direct_excludes;
CREATE VIEW playlist_direct_excludes AS
SELECT
  p.id AS parent_playlist_id,
  CAST(exc.value AS INTEGER) AS child_playlist_id
FROM playlists p
JOIN json_each(json_extract(p.rules_json, '$.exclude_playlists')) exc
  ON json_type(exc.value) IN ('integer', 'text')
WHERE json_array_length(json_extract(p.rules_json, '$.exclude_playlists')) > 0;

DROP VIEW IF EXISTS playlist_excludes_recursive;
CREATE VIEW playlist_excludes_recursive AS
WITH RECURSIVE rec_ex(parent_playlist_id, child_playlist_id) AS (
  SELECT parent_playlist_id, child_playlist_id FROM playlist_direct_excludes
  UNION ALL
  SELECT d.parent_playlist_id, di.child_playlist_id
  FROM playlist_direct_excludes d
  JOIN rec_ex di ON di.parent_playlist_id = d.child_playlist_id
)
SELECT DISTINCT parent_playlist_id AS parent_id, child_playlist_id AS child_id FROM rec_ex;


-- 6) vidéos apportées par les playlists incluses (manuelles + dynamic_base)
--    For each parent, collect videos that belong to any included child playlist (direct or transitive).
--    union logique (rules.logic = 'OR')
DROP VIEW IF EXISTS playlist_includes_union;
CREATE VIEW playlist_includes_union AS
-- union de base + vidéos incluses
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
FROM dynamic_playlist_videos_base db
WHERE
  json_extract((SELECT rules_json FROM playlists WHERE id = db.playlist_id), '$.logic') = 'OR'

UNION

SELECT DISTINCT iv.parent_playlist_id AS playlist_id,
       (SELECT name FROM playlists WHERE id = iv.parent_playlist_id) AS playlist_name,
       'dynamic' AS playlist_type,
       iv.video_file_name
FROM playlist_included_videos iv
JOIN playlists p ON p.id = iv.parent_playlist_id
WHERE json_extract(p.rules_json, '$.logic') = 'OR';



-- 7) intersection logique (rules.logic = 'AND')
DROP VIEW IF EXISTS playlist_includes_intersection;
CREATE VIEW playlist_includes_intersection AS
-- Cas 1️⃣ : AND + playlists incluses => intersection stricte
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
FROM dynamic_playlist_videos_base db
WHERE json_extract((SELECT rules_json FROM playlists WHERE id = db.playlist_id), '$.logic') = 'AND'
  AND json_array_length(json_extract((SELECT rules_json FROM playlists WHERE id = db.playlist_id), '$.include_playlists')) > 0
  AND db.video_file_name IN (
      SELECT iv.video_file_name
      FROM playlist_included_videos iv
      WHERE iv.parent_playlist_id = db.playlist_id
  )

UNION ALL

-- Cas 2️⃣ : AND + aucune playlist incluse => garder la base telle quelle
SELECT DISTINCT db.playlist_id, db.playlist_name, db.playlist_type, db.video_file_name
FROM dynamic_playlist_videos_base db
WHERE json_extract((SELECT rules_json FROM playlists WHERE id = db.playlist_id), '$.logic') = 'AND'
  AND (
    json_array_length(json_extract((SELECT rules_json FROM playlists WHERE id = db.playlist_id), '$.include_playlists')) IS NULL
    OR json_array_length(json_extract((SELECT rules_json FROM playlists WHERE id = db.playlist_id), '$.include_playlists')) = 0
  );




-- 8) regroupement des deux logiques
DROP VIEW IF EXISTS playlist_after_includes;
CREATE VIEW playlist_after_includes AS
SELECT * FROM playlist_includes_union
UNION ALL
SELECT * FROM playlist_includes_intersection;



-- 9) exclusions
DROP VIEW IF EXISTS playlist_excluded_videos;
CREATE VIEW playlist_excluded_videos AS
SELECT per.parent_id AS parent_playlist_id, mpv.video_file_name
FROM playlist_excludes_recursive per
JOIN manual_playlists_videos mpv ON mpv.playlist_id = per.child_id

UNION

SELECT per.parent_id AS parent_playlist_id, dpb.video_file_name
FROM playlist_excludes_recursive per
JOIN dynamic_playlist_videos_base dpb ON dpb.playlist_id = per.child_id;



-- 10)  Appliquer exclusions
DROP VIEW IF EXISTS playlist_after_excludes;
CREATE VIEW playlist_after_excludes AS
SELECT pai.playlist_id, pai.playlist_name, pai.playlist_type, pai.video_file_name
FROM playlist_after_includes pai
LEFT JOIN playlist_excluded_videos pev
  ON pev.parent_playlist_id = pai.playlist_id AND pev.video_file_name = pai.video_file_name
WHERE pev.parent_playlist_id IS NULL;

-- 11) résultat final « flat »

DROP VIEW IF EXISTS playlist_videos_flat;
CREATE VIEW playlist_videos_flat AS
SELECT playlist_id, playlist_name, playlist_type, video_file_name
FROM manual_playlists_videos
UNION ALL
SELECT playlist_id, playlist_name, playlist_type, video_file_name
FROM playlist_after_excludes;
