import requests
import os
import json
import re
from urllib.parse import urljoin
from html import unescape
import sqlite3
from uuid import uuid4
from datetime import datetime

def get_log_file_path():
    # Log folder will be in the same directory as the script
    script_dir = os.path.dirname(os.path.abspath(__file__))
    log_dir = os.path.join(script_dir, "log")
    os.makedirs(log_dir, exist_ok=True)
    date_str = datetime.now().strftime("%Y-%m-%d")
    log_file = os.path.join(log_dir, f"crawl_error_{date_str}.log")
    
    # Check file size and append a counter if larger than 5MB
    max_size = 5 * 1024 * 1024
    counter = 1
    base_log_file = log_file
    while os.path.exists(log_file) and os.path.getsize(log_file) > max_size:
        log_file = os.path.join(log_dir, f"crawl_error_{date_str}_{counter}.log")
        counter += 1
    return log_file

def log_error(movie_name, slug, error_msg, episode_name=None):
    log_file = get_log_file_path()
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    if episode_name:
        log_entry = f"[{timestamp}] Phim: {movie_name} (slug: {slug}) - Tập: {episode_name} - Lỗi: {error_msg}\n"
    else:
        log_entry = f"[{timestamp}] Phim: {movie_name} (slug: {slug}) - Lỗi: {error_msg}\n"
    with open(log_file, "a", encoding="utf-8") as f:
        f.write(log_entry)

def init_db(db_path="C:\\Apps\\Python\\kkphim\\data.db"):
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS movies (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            slug TEXT NOT NULL UNIQUE,
            name TEXT,
            origin_name TEXT,
            year TEXT,
            content TEXT,
            type TEXT,
            poster_url TEXT,
            thumb_url TEXT,
            time TEXT
        )
    ''')
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS m3u8_files (
            access_key TEXT PRIMARY KEY,
            movie_id INTEGER,
            m3u8_path TEXT NOT NULL,
            filename TEXT,
            FOREIGN KEY (movie_id) REFERENCES movies (id),
            UNIQUE (access_key),
            UNIQUE (movie_id, filename, m3u8_path)
        )
    ''')
    conn.commit()
    conn.close()

def generate_access_key():
    return str(uuid4())

def create_strm(movie_folder, m3u8_path, access_key, server="http://192.168.1.69:8000/"):
    try:
        strm_path = os.path.join(movie_folder, os.path.splitext(os.path.basename(m3u8_path))[0] + ".strm")
        strm_content = f"{server}{access_key}.m3u8"
        with open(strm_path, "w", encoding="utf-8") as f:
            f.write(strm_content)
    except Exception as e:
        log_error(os.path.basename(movie_folder), "unknown-slug", f"Lỗi khi tạo file STRM: {str(e)}", episode_name="STRM")

def sanitize_filename(name):
    invalid_chars = r'[<>:"|?*\x00-\x1F]'
    sanitized = re.sub(invalid_chars, '', name)
    sanitized = re.sub(r'\s+', ' ', sanitized).strip()
    sanitized = sanitized.replace('/', '-').replace('\\', '-')
    return sanitized

def clean_html_entities(text):
    return unescape(text)

def get_movie_kkphim(slug, path=None, skipad=True, replace=True, create_strm_file=False, 
                     path_db="C:\\Apps\\Python\\kkphim\\data.db", db_base_path=None):
    if path is None:
        path = os.getcwd()

    # Initialize database
    init_db(path_db)
    conn = sqlite3.connect(path_db)
    cursor = conn.cursor()

    try:
        # Fetch movie data from API first
        api_url = f"https://phimapi.com/phim/{slug}"
        try:
            response = requests.get(api_url)
            response.raise_for_status()
            data = response.json()
        except requests.RequestException as e:
            conn.close()
            return {"status": False, "msg": f"Lỗi khi gọi API: {str(e)}", "movie": {}, "errors": []}

        if not data.get("status", False):
            conn.close()
            return {"status": False, "msg": "API không trả về dữ liệu phim", "movie": {}, "errors": []}

        movie = data.get("movie", {})
        episodes = data.get("episodes", [])
        movie_name = sanitize_filename(movie.get("name", slug))

        # Check if movie already exists in DB
        cursor.execute("SELECT id FROM movies WHERE slug = ?", (slug,))
        movie_result = cursor.fetchone()
        
        # If movie exists and replace=True, delete old entries to overwrite
        if movie_result and replace:
            movie_id = movie_result[0]
            cursor.execute("DELETE FROM m3u8_files WHERE movie_id = ?", (movie_id,))
            cursor.execute("DELETE FROM movies WHERE id = ?", (movie_id,))
        elif movie_result and not replace:
            movie_id = movie_result[0]
        else:
            # Insert new movie into DB
            cursor.execute('''
                INSERT INTO movies (slug, name, origin_name, year, content, type, poster_url, thumb_url, time)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (slug, movie.get("name", ""), movie.get("origin_name", ""), movie.get("year", ""),
                  movie.get("content", ""), movie.get("type", "single"), movie.get("poster_url", ""),
                  movie.get("thumb_url", ""), movie.get("time", "")))
            movie_id = cursor.lastrowid

        movie_type = movie.get("type", "single")
        movie_folder = os.path.join(path, movie_name)
        try:
            os.makedirs(movie_folder, exist_ok=True)
        except Exception as e:
            conn.close()
            log_error(movie_name, slug, f"Lỗi khi tạo thư mục phim: {str(e)}")
            return {"status": False, "msg": f"Lỗi khi tạo thư mục phim: {str(e)}", "movie": movie, "errors": []}

        # Save poster
        poster_url = movie.get("poster_url", "")
        poster_path = os.path.join(movie_folder, "poster.jpg")
        if poster_url and (replace or not os.path.exists(poster_path)):
            try:
                poster_response = requests.get(poster_url)
                poster_response.raise_for_status()
                with open(poster_path, "wb") as f:
                    f.write(poster_response.content)
            except requests.RequestException as e:
                log_error(movie_name, slug, f"Lỗi khi tải poster: {str(e)}", episode_name="Poster")
            except Exception as e:
                log_error(movie_name, slug, f"Lỗi khi ghi file poster: {str(e)}", episode_name="Poster")

        # Save backdrop
        backdrop_url = movie.get("thumb_url", "")
        backdrop_path = os.path.join(movie_folder, "backdrop.jpg")
        if backdrop_url and (replace or not os.path.exists(backdrop_path)):
            try:
                backdrop_response = requests.get(backdrop_url)
                backdrop_response.raise_for_status()
                with open(backdrop_path, "wb") as f:
                    f.write(backdrop_response.content)
            except requests.RequestException as e:
                log_error(movie_name, slug, f"Lỗi khi tải backdrop: {str(e)}", episode_name="Backdrop")
            except Exception as e:
                log_error(movie_name, slug, f"Lỗi khi ghi file backdrop: {str(e)}", episode_name="Backdrop")

        season_match = re.search(r"(Season|Phần)\s*(\d+)", movie.get("name", ""), re.IGNORECASE)
        season_number = f"{int(season_match.group(2)):02}" if season_match else "01"

        errors = []  # Danh sách để lưu lỗi của từng tập
        episodes_processed = 0  # Đếm số tập xử lý thành công

        for server in episodes:
            for episode in server.get("server_data", []):
                filename = episode.get("filename", "")
                link_m3u8 = episode.get("link_m3u8", "")
                if not link_m3u8:
                    continue

                filename = re.sub(r"Tập\s+(\d+)", lambda m: f"S{season_number}E{int(m.group(1)):02}", filename)
                clean_filename = sanitize_filename(filename)
                m3u8_filename = f"{clean_filename}.m3u8"
                m3u8_path = os.path.join(movie_folder, m3u8_filename)

                # Determine the path to store in DB
                db_m3u8_path = m3u8_path
                if db_base_path:
                    relative_path = os.path.relpath(m3u8_path, start=path)
                    db_m3u8_path = os.path.join(db_base_path, relative_path).replace(os.sep, '/')

                # Check if M3U8 entry exists in DB
                cursor.execute('''
                    SELECT access_key FROM m3u8_files 
                    WHERE movie_id = ? AND filename = ? AND m3u8_path = ?
                ''', (movie_id, clean_filename, db_m3u8_path))
                m3u8_result = cursor.fetchone()

                # Chỉ bỏ qua nếu replace=False, file M3U8 tồn tại, và bản ghi trong DB hợp lệ
                if not replace and os.path.exists(m3u8_path) and m3u8_result:
                    episodes_processed += 1
                    continue

                try:
                    # Generate new access key
                    access_key = generate_access_key()

                    m3u8_response = requests.get(link_m3u8)
                    m3u8_response.raise_for_status()
                    master_content = m3u8_response.text

                    base_url = urljoin(link_m3u8, ".")
                    variant_url = None
                    for line in master_content.splitlines():
                        if line.startswith("#EXT-X-STREAM-INF"):
                            next_line = master_content.splitlines()[master_content.splitlines().index(line) + 1]
                            if not next_line.startswith("#"):
                                variant_url = urljoin(base_url, next_line)
                                break

                    if variant_url:
                        variant_response = requests.get(variant_url)
                        variant_response.raise_for_status()
                        variant_content = variant_response.text
                        base_variant_url = urljoin(variant_url, ".")
                        new_m3u8_content = []
                        skip_ad = False
                        for line in variant_content.splitlines():
                            if skipad and line.strip() == "#EXT-X-DISCONTINUITY":
                                skip_ad = not skip_ad
                                continue
                            if skipad and skip_ad and line.endswith(".ts"):
                                continue
                            if skipad and skip_ad and line.startswith("#EXTINF"):
                                continue
                            if line.endswith(".ts"):
                                absolute_ts_url = urljoin(base_variant_url, line)
                                new_m3u8_content.append(absolute_ts_url)
                            else:
                                new_m3u8_content.append(line)
                        with open(m3u8_path, "w", encoding="utf-8") as f:
                            f.write("\n".join(new_m3u8_content))
                    else:
                        new_m3u8_content = []
                        skip_ad = False
                        for line in master_content.splitlines():
                            if skipad and line.strip() == "#EXT-X-DISCONTINUITY":
                                skip_ad = not skip_ad
                                continue
                            if skipad and skip_ad and line.endswith(".ts"):
                                continue
                            if skipad and skip_ad and line.startswith("#EXTINF"):
                                continue
                            if line.endswith(".ts"):
                                absolute_ts_url = urljoin(base_url, line)
                                new_m3u8_content.append(absolute_ts_url)
                            else:
                                new_m3u8_content.append(line)
                        with open(m3u8_path, "w", encoding="utf-8") as f:
                            f.write("\n".join(new_m3u8_content))

                    # Luôn cập nhật hoặc thêm bản ghi vào database
                    if m3u8_result and replace:
                        cursor.execute('''
                            UPDATE m3u8_files 
                            SET access_key = ?
                            WHERE movie_id = ? AND filename = ? AND m3u8_path = ?
                        ''', (access_key, movie_id, clean_filename, db_m3u8_path))
                    else:
                        cursor.execute('''
                            INSERT OR REPLACE INTO m3u8_files (access_key, movie_id, m3u8_path, filename)
                            VALUES (?, ?, ?, ?)
                        ''', (access_key, movie_id, db_m3u8_path, clean_filename))

                    if create_strm_file:
                        create_strm(movie_folder, m3u8_path, access_key)

                    episodes_processed += 1

                except requests.RequestException as e:
                    log_error(movie_name, slug, f"Lỗi khi xử lý M3U8: {str(e)}", episode_name=clean_filename)
                    errors.append({"episode": clean_filename, "error": f"Lỗi khi xử lý M3U8: {str(e)}"})
                    continue  # Tiếp tục xử lý tập tiếp theo thay vì thoát

        # Save NFO file
        nfo_path = os.path.join(movie_folder, "movie.nfo" if movie_type == "single" else "tvshow.nfo")
        if replace or not os.path.exists(nfo_path):
            # Handle potential null values for imdbid and tmdbid
            imdb_id = movie.get("imdb", {}).get("id", "") if movie.get("imdb") else ""
            tmdb_id = movie.get("tmdb", {}).get("id", "") if movie.get("tmdb") else ""
            nfo_content = f"""<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>
<{movie_type if movie_type == 'single' else 'tvshow'}>
    <title>{movie.get("name", "")}</title>
    <originaltitle>{movie.get("origin_name", "")}</originaltitle>
    <plot>{clean_html_entities(movie.get("content", ""))}</plot>
    <year>{movie.get("year", "")}</year>
    <thumb>{movie.get("thumb_url", "")}</thumb>
    <fanart>{movie.get("thumb_url", "")}</fanart>
    <poster>poster.jpg</poster>
    <runtime>{movie.get("time", "").replace(" phút", "")}</runtime>
    <imdbid>{imdb_id}</imdbid>
    <tmdbid>{tmdb_id}</tmdbid>
"""
            for actor in movie.get("actor", []):
                nfo_content += f"    <actor><name>{actor}</name></actor>\n"
            for director in movie.get("director", []):
                nfo_content += f"    <director>{director}</director>\n"
            for category in movie.get("category", []):
                nfo_content += f"    <genre>{category.get('name', '')}</genre>\n"
            for country in movie.get("country", []):
                nfo_content += f"    <country>{country.get('name', '')}</country>\n"
            nfo_content += f"</{movie_type if movie_type == 'single' else 'tvshow'}>"
            try:
                with open(nfo_path, "w", encoding="utf-8") as f:
                    f.write(nfo_content)
            except Exception as e:
                log_error(movie_name, slug, f"Lỗi khi ghi file NFO: {str(e)}", episode_name="NFO")
                errors.append({"episode": "NFO", "error": f"Lỗi khi ghi file NFO: {str(e)}"})

        conn.commit()
        conn.close()

        # Trả về trạng thái dựa trên việc có tập nào xử lý thành công hay không
        status = episodes_processed > 0
        msg = "Phim, M3U8 với link .ts tuyệt đối, NFO và STRM (nếu chọn) đã được xử lý, một số tập có thể gặp lỗi" if errors else "Phim, M3U8 với link .ts tuyệt đối, NFO và STRM (nếu chọn) đã được xử lý thành công"
        return {"status": status, "msg": msg, "movie": movie, "errors": errors}
    
    except Exception as e:
        conn.close()
        log_error(movie_name, slug, f"Lỗi không xác định: {str(e)}")
        return {"status": False, "msg": f"Lỗi không xác định: {str(e)}", "movie": {}, "errors": []}

# ... (Hàm get_movie_ophim tương tự, thêm try-except cho việc ghi file poster/backdrop) ...
def get_movie_ophim(slug, path=None, skipad=True, replace=True, create_strm_file=False, 
                   path_db="C:\\Apps\\Python\\kkphim\\data.db", db_base_path=None):
    if path is None:
        path = os.getcwd()

    # Khởi tạo cơ sở dữ liệu
    init_db(path_db)
    conn = sqlite3.connect(path_db)
    cursor = conn.cursor()

    try:
        # Lấy dữ liệu phim từ ophim API
        api_url = f"https://ophim1.com/phim/{slug}"
        try:
            response = requests.get(api_url)
            response.raise_for_status()
            data = response.json()
        except requests.RequestException as e:
            conn.close()
            return {"status": False, "msg": f"Lỗi khi gọi API: {str(e)}", "movie": {}, "errors": []}

        if not data.get("status", False):
            conn.close()
            return {"status": False, "msg": "API không trả về dữ liệu phim", "movie": {}, "errors": []}

        movie = data.get("movie", {})
        episodes = data.get("episodes", [])
        movie_name = sanitize_filename(movie.get("name", slug))

        # Kiểm tra phim đã tồn tại trong DB chưa
        cursor.execute("SELECT id FROM movies WHERE slug = ?", (slug,))
        movie_result = cursor.fetchone()
        
        # Nếu phim tồn tại và replace=True, xóa các mục cũ để ghi đè
        if movie_result and replace:
            movie_id = movie_result[0]
            cursor.execute("DELETE FROM m3u8_files WHERE movie_id = ?", (movie_id,))
            cursor.execute("DELETE FROM movies WHERE id = ?", (movie_id,))
        elif movie_result and not replace:
            movie_id = movie_result[0]
        else:
            # Thêm phim mới vào DB
            cursor.execute('''
                INSERT INTO movies (slug, name, origin_name, year, content, type, poster_url, thumb_url, time)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (slug, movie.get("name", ""), movie.get("origin_name", ""), movie.get("year", ""),
                  movie.get("content", ""), movie.get("type", "single"), movie.get("poster_url", ""),
                  movie.get("thumb_url", ""), movie.get("time", "")))
            movie_id = cursor.lastrowid

        movie_type = movie.get("type", "single")
        movie_folder = os.path.join(path, movie_name)
        try:
            os.makedirs(movie_folder, exist_ok=True)
        except Exception as e:
            conn.close()
            log_error(movie_name, slug, f"Lỗi khi tạo thư mục phim: {str(e)}")
            return {"status": False, "msg": f"Lỗi khi tạo thư mục phim: {str(e)}", "movie": movie, "errors": []}

        # Lưu poster
        poster_url = movie.get("poster_url", "")
        poster_path = os.path.join(movie_folder, "poster.jpg")
        if poster_url and (replace or not os.path.exists(poster_path)):
            try:
                poster_response = requests.get(poster_url)
                poster_response.raise_for_status()
                with open(poster_path, "wb") as f:
                    f.write(poster_response.content)
            except requests.RequestException as e:
                log_error(movie_name, slug, f"Lỗi khi tải poster: {str(e)}", episode_name="Poster")
            except Exception as e:
                log_error(movie_name, slug, f"Lỗi khi ghi file poster: {str(e)}", episode_name="Poster")

        # Lưu backdrop
        backdrop_url = movie.get("thumb_url", "")
        backdrop_path = os.path.join(movie_folder, "backdrop.jpg")
        if backdrop_url and (replace or not os.path.exists(backdrop_path)):
            try:
                backdrop_response = requests.get(backdrop_url)
                backdrop_response.raise_for_status()
                with open(backdrop_path, "wb") as f:
                    f.write(backdrop_response.content)
            except requests.RequestException as e:
                log_error(movie_name, slug, f"Lỗi khi tải backdrop: {str(e)}", episode_name="Backdrop")
            except Exception as e:
                log_error(movie_name, slug, f"Lỗi khi ghi file backdrop: {str(e)}", episode_name="Backdrop")

        season_match = re.search(r"(Season|Phần)\s*(\d+)", movie.get("name", ""), re.IGNORECASE)
        season_number = f"{int(season_match.group(2)):02}" if season_match else "01"

        errors = []  # Danh sách để lưu lỗi của từng tập
        episodes_processed = 0  # Đếm số tập xử lý thành công

        for server in episodes:
            # Loại bỏ các ký tự như " #1", " #2" khỏi server_name
            server_name = re.sub(r'\s*#\d+', '', server.get("server_name", "")).strip()
            for episode in server.get("server_data", []):
                filename = episode.get("filename", "")
                link_m3u8 = episode.get("link_m3u8", "")
                if not link_m3u8:
                    continue

                # Đặt tên tập phim cho phim bộ (tvshow) và phim lẻ (single)
                episode_slug = episode.get("slug", "")
                if movie_type == "single":
                    clean_filename = sanitize_filename(f"{movie.get('name', slug)} - {movie.get('origin_name', '')} - {movie.get('year', '')} - {server_name}")
                else:
                    episode_number = f"S{season_number}E{int(episode_slug):02}" if episode_slug.isdigit() else f"S{season_number}E01"
                    clean_filename = sanitize_filename(f"{movie.get('name', slug)} - {movie.get('origin_name', '')} - {movie.get('year', '')} - {episode_number} - {server_name}")

                m3u8_filename = f"{clean_filename}.m3u8"
                m3u8_path = os.path.join(movie_folder, m3u8_filename)

                # Xác định đường dẫn lưu trong DB
                db_m3u8_path = m3u8_path
                if db_base_path:
                    relative_path = os.path.relpath(m3u8_path, start=path)
                    db_m3u8_path = os.path.join(db_base_path, relative_path).replace(os.sep, '/')

                # Kiểm tra mục M3U8 đã tồn tại trong DB chưa
                cursor.execute('''
                    SELECT access_key FROM m3u8_files 
                    WHERE movie_id = ? AND filename = ? AND m3u8_path = ?
                ''', (movie_id, clean_filename, db_m3u8_path))
                m3u8_result = cursor.fetchone()

                # Bỏ qua nếu replace=False và file tồn tại và có trong DB
                if not replace and os.path.exists(m3u8_path) and m3u8_result:
                    episodes_processed += 1
                    continue

                try:
                    m3u8_response = requests.get(link_m3u8)
                    m3u8_response.raise_for_status()
                    master_content = m3u8_response.text

                    base_url = urljoin(link_m3u8, ".")
                    variant_url = None
                    for line in master_content.splitlines():
                        if line.startswith("#EXT-X-STREAM-INF"):
                            next_line = master_content.splitlines()[master_content.splitlines().index(line) + 1]
                            if not next_line.startswith("#"):
                                variant_url = urljoin(base_url, next_line)
                                break

                    # Tạo access key mới
                    access_key = generate_access_key()

                    if variant_url:
                        variant_response = requests.get(variant_url)
                        variant_response.raise_for_status()
                        variant_content = variant_response.text
                        base_variant_url = urljoin(variant_url, ".")
                        new_m3u8_content = []
                        lines = variant_content.splitlines()
                        i = 0
                        while i < len(lines):
                            line = lines[i].strip()
                            if skipad and line == "#EXT-X-DISCONTINUITY":
                                # Định nghĩa chuỗi pattern quảng cáo chính xác
                                ad_pattern = [
                                    "#EXT-X-DISCONTINUITY",
                                    "#EXTINF:3.920000,", "ts",
                                    "#EXTINF:0.760000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:2.500000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:2.420000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:0.780000,", "ts",
                                    "#EXTINF:1.960000,", "ts",
                                    "#EXT-X-DISCONTINUITY",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:1.760000,", "ts",
                                    "#EXTINF:3.200000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:1.360000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:0.720000,", "ts"
                                ]
                                pattern_matched = True
                                if i + len(ad_pattern) <= len(lines):
                                    for k, expected in enumerate(ad_pattern):
                                        check_idx = i + k
                                        if expected == "ts":
                                            if check_idx >= len(lines) or not lines[check_idx].strip().endswith(".ts"):
                                                pattern_matched = False
                                                break
                                        else:
                                            if check_idx >= len(lines) or lines[check_idx].strip() != expected:
                                                pattern_matched = False
                                                break
                                    if pattern_matched:
                                        i += len(ad_pattern)  # Bỏ qua toàn bộ chuỗi quảng cáo
                                        continue
                            # Bỏ qua dòng #EXT-X-DISCONTINUITY nếu không thuộc chuỗi quảng cáo
                            if line == "#EXT-X-DISCONTINUITY":
                                i += 1
                                continue
                            if line.endswith(".ts"):
                                absolute_ts_url = urljoin(base_variant_url, line)
                                new_m3u8_content.append(absolute_ts_url)
                            else:
                                new_m3u8_content.append(line)
                            i += 1
                        with open(m3u8_path, "w", encoding="utf-8") as f:
                            f.write("\n".join(new_m3u8_content))
                    else:
                        new_m3u8_content = []
                        lines = master_content.splitlines()
                        i = 0
                        while i < len(lines):
                            line = lines[i].strip()
                            if skipad and line == "#EXT-X-DISCONTINUITY":
                                # Định nghĩa chuỗi pattern quảng cáo chính xác
                                ad_pattern = [
                                    "#EXT-X-DISCONTINUITY",
                                    "#EXTINF:3.920000,", "ts",
                                    "#EXTINF:0.760000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:2.500000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:2.420000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:0.780000,", "ts",
                                    "#EXTINF:1.960000,", "ts",
                                    "#EXT-X-DISCONTINUITY",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:1.760000,", "ts",
                                    "#EXTINF:3.200000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:1.360000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:2.000000,", "ts",
                                    "#EXTINF:0.720000,", "ts"
                                ]
                                pattern_matched = True
                                if i + len(ad_pattern) <= len(lines):
                                    for k, expected in enumerate(ad_pattern):
                                        check_idx = i + k
                                        if expected == "ts":
                                            if check_idx >= len(lines) or not lines[check_idx].strip().endswith(".ts"):
                                                pattern_matched = False
                                                break
                                        else:
                                            if check_idx >= len(lines) or lines[check_idx].strip() != expected:
                                                pattern_matched = False
                                                break
                                    if pattern_matched:
                                        i += len(ad_pattern)  # Bỏ qua toàn bộ chuỗi quảng cáo
                                        continue
                            # Bỏ qua dòng #EXT-X-DISCONTINUITY nếu không thuộc chuỗi quảng cáo
                            if line == "#EXT-X-DISCONTINUITY":
                                i += 1
                                continue
                            if line.endswith(".ts"):
                                absolute_ts_url = urljoin(base_url, line)
                                new_m3u8_content.append(absolute_ts_url)
                            else:
                                new_m3u8_content.append(line)
                            i += 1
                        with open(m3u8_path, "w", encoding="utf-8") as f:
                            f.write("\n".join(new_m3u8_content))

                    # Tạo access key mới
                    if m3u8_result and replace:
                        # Nếu replace=True, cập nhật access key mới
                        cursor.execute('''
                            UPDATE m3u8_files 
                            SET access_key = ?
                            WHERE movie_id = ? AND filename = ? AND m3u8_path = ?
                        ''', (access_key, movie_id, clean_filename, db_m3u8_path))
                    else:
                        # Nếu chưa có mục, thêm mới
                        cursor.execute('''
                            INSERT OR REPLACE INTO m3u8_files (access_key, movie_id, m3u8_path, filename)
                            VALUES (?, ?, ?, ?)
                        ''', (access_key, movie_id, db_m3u8_path, clean_filename))

                    if create_strm_file:
                        create_strm(movie_folder, m3u8_path, access_key, server="http://192.168.1.69:8001/")

                    episodes_processed += 1

                except requests.RequestException as e:
                    log_error(movie_name, slug, f"Lỗi khi xử lý M3U8: {str(e)}", episode_name=clean_filename)
                    errors.append({"episode": clean_filename, "error": f"Lỗi khi xử lý M3U8: {str(e)}"})
                    continue

        # Lưu file NFO
        nfo_path = os.path.join(movie_folder, "movie.nfo" if movie_type == "single" else "tvshow.nfo")
        if replace or not os.path.exists(nfo_path):
            # Handle potential null values for imdbid and tmdbid
            imdb_id = movie.get("imdb", {}).get("id", "") if movie.get("imdb") else ""
            tmdb_id = movie.get("tmdb", {}).get("id", "") if movie.get("tmdb") else ""
            nfo_content = f"""<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>
<{movie_type if movie_type == 'single' else 'tvshow'}>
    <title>{movie.get("name", "")}</title>
    <originaltitle>{movie.get("origin_name", "")}</originaltitle>
    <plot>{clean_html_entities(movie.get("content", ""))}</plot>
    <year>{movie.get("year", "")}</year>
    <thumb>{movie.get("thumb_url", "")}</thumb>
    <fanart>{movie.get("thumb_url", "")}</fanart>
    <poster>poster.jpg</poster>
    <runtime>{movie.get("time", "").replace(" phút/tập", "").replace(" phút", "")}</runtime>
    <imdbid>{imdb_id}</imdbid>
    <tmdbid>{tmdb_id}</tmdbid>
"""
            for actor in movie.get("actor", []):
                nfo_content += f"    <actor><name>{actor}</name></actor>\n"
            for director in movie.get("director", []):
                nfo_content += f"    <director>{director}</director>\n"
            for category in movie.get("category", []):
                nfo_content += f"    <genre>{category.get('name', '')}</genre>\n"
            for country in movie.get("country", []):
                nfo_content += f"    <country>{country.get('name', '')}</country>\n"
            nfo_content += f"</{movie_type if movie_type == 'single' else 'tvshow'}>"
            try:
                with open(nfo_path, "w", encoding="utf-8") as f:
                    f.write(nfo_content)
            except Exception as e:
                log_error(movie_name, slug, f"Lỗi khi ghi file NFO: {str(e)}", episode_name="NFO")
                errors.append({"episode": "NFO", "error": f"Lỗi khi ghi file NFO: {str(e)}"})

        conn.commit()
        conn.close()
        status = episodes_processed > 0
        msg = "Phim, M3U8 với link .ts tuyệt đối, NFO và STRM (nếu chọn) đã được xử lý, một số tập có thể gặp lỗi" if errors else "Phim, M3U8 với link .ts tuyệt đối, NFO và STRM (nếu chọn) đã được xử lý thành công"
        return {"status": status, "msg": msg, "movie": movie, "errors": errors}
    
    except Exception as e:
        conn.close()
        log_error(movie_name, slug, f"Lỗi không xác định: {str(e)}")
        return {"status": False, "msg": f"Lỗi không xác định: {str(e)}", "movie": {}, "errors": []}