# --- Standard Library Imports ---
import json
import os
import sys
import threading
import time
import unicodedata
from collections import defaultdict
from urllib.parse import urlparse

# --- PyQt5 Imports ---
from PyQt5.QtCore import pyqtSignal, QCoreApplication, QSize, QThread, QTimer, Qt
from PyQt5.QtWidgets import (
    QApplication, QDialog, QHBoxLayout, QLabel, QLineEdit, QListWidget,
    QListWidgetItem, QMessageBox, QPushButton, QVBoxLayout, QAbstractItemView,
    QSplitter, QProgressBar, QWidget, QFileDialog  
)

# --- Local Application Imports ---
from ...i18n.translator import get_translation
from ..main_window import get_app_icon_object
from ...core.api_client import download_from_api
from ...utils.network_utils import extract_post_info, prepare_cookies_for_request
from ...utils.resolution import get_dark_theme


class PostsFetcherThread (QThread ):
    status_update =pyqtSignal (str )
    posts_fetched_signal =pyqtSignal (object ,list )
    fetch_error_signal =pyqtSignal (object ,str )
    finished_signal =pyqtSignal ()

    def __init__ (self ,creators_to_fetch ,parent_dialog_ref ):
        super ().__init__ ()
        self .creators_to_fetch =creators_to_fetch 
        self .parent_dialog =parent_dialog_ref 
        self .cancellation_flag =threading .Event ()

    def cancel (self ):
        self .cancellation_flag .set ()
        self .status_update .emit (self .parent_dialog ._tr ("post_fetch_cancelled_status","Post fetching cancellation requested..."))

    def run (self ):
        if not self .creators_to_fetch :
            self .status_update .emit (self .parent_dialog ._tr ("no_creators_to_fetch_status","No creators selected to fetch posts for."))
            self .finished_signal .emit ()
            return 

        for creator_data in self .creators_to_fetch :
            if self .cancellation_flag .is_set ():
                break 

            creator_name =creator_data .get ('name','Unknown Creator')
            service =creator_data .get ('service')
            user_id =creator_data .get ('id')

            print(f"[DEBUG] Fetching posts for: name={creator_name}, service={service}, user_id={user_id}")

            if not service or not user_id :
                self .fetch_error_signal .emit (creator_data ,f"Missing service or ID for {creator_name }")
                continue 

            self .status_update .emit (self .parent_dialog ._tr ("fetching_posts_for_creator_status_all_pages","Fetching all posts for {creator_name} ({service})... This may take a while.").format (creator_name =creator_name ,service =service ))

            domain =self .parent_dialog ._get_domain_for_service (service )
            api_url_base =f"https://{domain }/api/v1/{service }/user/{user_id }"
            print(f"[DEBUG] API URL: {api_url_base}")


            use_cookie_param =False 
            cookie_text_param =""
            selected_cookie_file_param =None 
            app_base_dir_param =None 

            if self .parent_dialog .parent_app :
                app =self .parent_dialog .parent_app 
                use_cookie_param =app .use_cookie_checkbox .isChecked ()
                cookie_text_param =app .cookie_text_input .text ().strip ()
                selected_cookie_file_param =app .selected_cookie_filepath 
                app_base_dir_param =app .app_base_dir 

            all_posts_for_this_creator =[]
            try :
                post_generator =download_from_api (
                api_url_base ,
                logger =lambda msg :self .status_update .emit (f"[API Fetch - {creator_name }] {msg }"),

                use_cookie =use_cookie_param ,
                cookie_text =cookie_text_param ,
                selected_cookie_file =selected_cookie_file_param ,
                app_base_dir =app_base_dir_param ,
                manga_filename_style_for_sort_check =None ,
                cancellation_event =self .cancellation_flag 
                )

                for posts_batch in post_generator :
                    if self .cancellation_flag .is_set ():
                        self .status_update .emit (f"Post fetching for {creator_name } cancelled during pagination.")
                        break 
                    all_posts_for_this_creator .extend (posts_batch )
                    print(f"[DEBUG] Fetched batch: {len(posts_batch)} posts, total so far: {len(all_posts_for_this_creator)}")
                    self .status_update .emit (f"Fetched {len (all_posts_for_this_creator )} posts so far for {creator_name }...")

                print(f"[DEBUG] Finished fetching for {creator_name}: {len(all_posts_for_this_creator)} posts total.")
                if not self .cancellation_flag .is_set ():
                    self .posts_fetched_signal .emit (creator_data ,all_posts_for_this_creator )
                    self .status_update .emit (f"Finished fetching {len (all_posts_for_this_creator )} posts for {creator_name }.")
                else :
                    self .posts_fetched_signal .emit (creator_data ,all_posts_for_this_creator )
                    self .status_update .emit (f"Fetching for {creator_name } cancelled. {len (all_posts_for_this_creator )} posts collected.")

            except RuntimeError as e :
                print(f"[DEBUG] RuntimeError for {creator_name}: {e}")
                if "cancelled by user"in str (e ).lower ()or self .cancellation_flag .is_set ():
                    self .status_update .emit (f"Post fetching for {creator_name } cancelled: {e }")
                    self .posts_fetched_signal .emit (creator_data ,all_posts_for_this_creator )
                else :
                    self .fetch_error_signal .emit (creator_data ,f"Runtime error fetching posts for {creator_name }: {e }")
            except Exception as e :
                print(f"[DEBUG] Exception for {creator_name}: {e}")
                self .fetch_error_signal .emit (creator_data ,f"Error fetching posts for {creator_name }: {e }")

            if self .cancellation_flag .is_set ():
                break 
            QThread .msleep (200 )

        if self .cancellation_flag .is_set ():
            self .status_update .emit (self .parent_dialog ._tr ("post_fetch_cancelled_status_done","Post fetching cancelled."))
        else :
            self .status_update .emit (self .parent_dialog ._tr ("post_fetch_finished_status","Finished fetching posts for selected creators."))
        self .finished_signal .emit ()


class EmptyPopupDialog (QDialog ):
    """A simple empty popup dialog."""
    SCOPE_CHARACTERS ="Characters"
    INITIAL_LOAD_LIMIT =200 
    SCOPE_CREATORS ="Creators"


    def __init__ (self ,app_base_dir ,parent_app_ref ,parent =None ):
        super ().__init__ (parent )
        self.parent_app = parent_app_ref

        scale_factor = getattr(self.parent_app, 'scale_factor', 1.0)
        
        self.setMinimumSize(int(400 * scale_factor), int(300 * scale_factor))
        self.current_scope_mode = self.SCOPE_CREATORS
        self .app_base_dir =app_base_dir 

        app_icon =get_app_icon_object ()
        if app_icon and not app_icon .isNull ():
            self .setWindowIcon (app_icon )
        self.update_profile_data = None
        self.update_creator_name = None
        self .selected_creators_for_queue =[]
        self .globally_selected_creators ={}
        self .fetched_posts_data ={}
        self .post_fetch_thread =None 
        self .TITLE_COLUMN_WIDTH_FOR_POSTS =70 
        self .globally_selected_post_ids =set ()
        self ._is_scrolling_titles =False 
        self ._is_scrolling_dates =False 


        dialog_layout =QHBoxLayout (self )
        self .setLayout (dialog_layout )



        self .left_pane_widget =QWidget ()
        left_pane_layout =QVBoxLayout (self .left_pane_widget )


        search_fetch_layout =QHBoxLayout ()
        self .search_input =QLineEdit ()
        self .search_input .textChanged .connect (self ._filter_list )
        search_fetch_layout .addWidget (self .search_input ,1 )
        self .fetch_posts_button =QPushButton ()
        self .fetch_posts_button .setEnabled (False )
        self .fetch_posts_button .clicked .connect (self ._handle_fetch_posts_click )
        search_fetch_layout .addWidget (self .fetch_posts_button )
        left_pane_layout .addLayout (search_fetch_layout )

        self .progress_bar =QProgressBar ()
        self .progress_bar .setRange (0 ,0 )
        self .progress_bar .setTextVisible (False )
        self .progress_bar .setVisible (False )
        left_pane_layout .addWidget (self .progress_bar )

        self .list_widget =QListWidget ()
        self .list_widget .itemChanged .connect (self ._handle_item_check_changed )
        left_pane_layout .addWidget (self .list_widget )


        left_bottom_buttons_layout =QHBoxLayout ()
        self .add_selected_button =QPushButton ()
        self .add_selected_button .setToolTip (
        "Add Selected Creators to URL Input\n\n"
        "Adds the names of all checked creators to the main URL input field,\n"
        "comma-separated, and closes this dialog."
        )
        self .add_selected_button .clicked .connect (self ._handle_add_selected )
        self .add_selected_button .setDefault (True )
        left_bottom_buttons_layout .addWidget (self .add_selected_button )
        self .scope_button =QPushButton ()
        self .scope_button .clicked .connect (self ._toggle_scope_mode )
        left_bottom_buttons_layout .addWidget (self .scope_button )
        left_pane_layout .addLayout (left_bottom_buttons_layout )
        self.update_button = QPushButton()
        self.update_button.clicked.connect(self._handle_update_check) 
        left_bottom_buttons_layout.addWidget(self.update_button)


        self .right_pane_widget =QWidget ()
        right_pane_layout =QVBoxLayout (self .right_pane_widget )

        self .posts_area_title_label =QLabel ("Fetched Posts")
        self .posts_area_title_label .setAlignment (Qt .AlignCenter )
        right_pane_layout .addWidget (self .posts_area_title_label )

        self .posts_search_input =QLineEdit ()
        self .posts_search_input .setVisible (False )

        self .posts_search_input .textChanged .connect (self ._filter_fetched_posts_list )
        right_pane_layout .addWidget (self .posts_search_input )


        posts_headers_layout =QHBoxLayout ()
        self .posts_title_header_label =QLabel ()
        self .posts_title_header_label .setStyleSheet ("font-weight: bold; padding-left: 20px;")
        posts_headers_layout .addWidget (self .posts_title_header_label ,7 )

        self .posts_date_header_label =QLabel ()
        self .posts_date_header_label .setStyleSheet ("font-weight: bold;")
        posts_headers_layout .addWidget (self .posts_date_header_label ,3 )
        right_pane_layout .addLayout (posts_headers_layout )



        self .posts_content_splitter =QSplitter (Qt .Horizontal )

        self .posts_title_list_widget =QListWidget ()
        self .posts_title_list_widget .itemChanged .connect (self ._handle_post_item_check_changed )
        self .posts_title_list_widget .setAlternatingRowColors (True )
        self .posts_content_splitter .addWidget (self .posts_title_list_widget )

        self .posts_date_list_widget =QListWidget ()
        self .posts_date_list_widget .setSelectionMode (QAbstractItemView .NoSelection )
        self .posts_date_list_widget .setAlternatingRowColors (True )
        self .posts_date_list_widget .setHorizontalScrollBarPolicy (Qt .ScrollBarAlwaysOff )
        self .posts_content_splitter .addWidget (self .posts_date_list_widget )

        right_pane_layout .addWidget (self .posts_content_splitter ,1 )

        posts_buttons_top_layout =QHBoxLayout ()
        self .posts_select_all_button =QPushButton ()
        self .posts_select_all_button .clicked .connect (self ._handle_posts_select_all )
        posts_buttons_top_layout .addWidget (self .posts_select_all_button )

        self .posts_deselect_all_button =QPushButton ()
        self .posts_deselect_all_button .clicked .connect (self ._handle_posts_deselect_all )
        posts_buttons_top_layout .addWidget (self .posts_deselect_all_button )
        right_pane_layout .addLayout (posts_buttons_top_layout )

        posts_buttons_bottom_layout =QHBoxLayout ()
        self .posts_add_selected_button =QPushButton ()
        self .posts_add_selected_button .clicked .connect (self ._handle_posts_add_selected_to_queue )
        posts_buttons_bottom_layout .addWidget (self .posts_add_selected_button )

        self .posts_close_button =QPushButton ()
        self .posts_close_button .clicked .connect (self ._handle_posts_close_view )
        posts_buttons_bottom_layout .addWidget (self .posts_close_button )
        right_pane_layout .addLayout (posts_buttons_bottom_layout )

        self .right_pane_widget .hide ()





        self .main_splitter =QSplitter (Qt .Horizontal )
        self .main_splitter .addWidget (self .left_pane_widget )
        self .main_splitter .addWidget (self .right_pane_widget )
        self .main_splitter .setCollapsible (0 ,False )
        self .main_splitter .setCollapsible (1 ,True )


        self .posts_title_list_widget .verticalScrollBar ().valueChanged .connect (self ._sync_scroll_dates )
        self .posts_date_list_widget .verticalScrollBar ().valueChanged .connect (self ._sync_scroll_titles )
        dialog_layout .addWidget (self .main_splitter )

        self .original_size =self .sizeHint ()
        self .main_splitter .setSizes ([int (self .width ()*scale_factor ),0 ])

        self ._retranslate_ui ()

        if self.parent_app and self.parent_app.current_theme == "dark":
            # Get the scale factor from the parent app
            scale = getattr(self.parent_app, 'scale_factor', 1)
            # Call the imported function with the correct scale
            self.setStyleSheet(get_dark_theme(scale))
        else:
            # Explicitly set a blank stylesheet for light mode
            self.setStyleSheet("")

        self .resize (int ((self .original_size .width ()+50 )*scale_factor ),int ((self .original_size .height ()+100 )*scale_factor ))

        QTimer .singleShot (0 ,self ._perform_initial_load )

    def _center_on_screen (self ):
        """Centers the dialog on the parent's screen or the primary screen."""
        if self .parent_app :
            parent_rect =self .parent_app .frameGeometry ()
            self .move (parent_rect .center ()-self .rect ().center ())
        else :
            try :
                screen_geo =QApplication .primaryScreen ().availableGeometry ()
                self .move (screen_geo .center ()-self .rect ().center ())
            except AttributeError :
                pass 

    def _handle_update_check(self):
        """Opens a dialog to select a creator profile and loads it for an update session."""
        appdata_dir = os.path.join(self.app_base_dir, "appdata")
        profiles_dir = os.path.join(appdata_dir, "creator_profiles")
        
        if not os.path.isdir(profiles_dir):
            QMessageBox.warning(self, "Directory Not Found", f"The creator profiles directory does not exist yet.\n\nPath: {profiles_dir}")
            return

        filepath, _ = QFileDialog.getOpenFileName(self, "Select Creator Profile for Update", profiles_dir, "JSON Files (*.json)")

        if filepath:
            try:
                with open(filepath, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                
                if 'creator_url' not in data or 'processed_post_ids' not in data:
                    raise ValueError("Invalid profile format.")

                self.update_profile_data = data
                self.update_creator_name = os.path.basename(filepath).replace('.json', '')
                self.accept() # Close the dialog and signal success
            except Exception as e:
                QMessageBox.critical(self, "Error Loading Profile", f"Could not load or parse the selected profile file:\n\n{e}")

    def _handle_fetch_posts_click (self ):
        selected_creators =list (self .globally_selected_creators .values ())
        print(f"[DEBUG] Selected creators for fetch: {selected_creators}")
        if not selected_creators :
            QMessageBox .information (self ,self ._tr ("no_selection_title","No Selection"),
            "Please select at least one creator to fetch posts for.")
            return 

        if self .parent_app :
            parent_geometry =self .parent_app .geometry ()
            new_width =int (parent_geometry .width ()*0.75 )
            new_height =int (parent_geometry .height ()*0.80 )
            self .resize (new_width ,new_height )
            self ._center_on_screen ()

        self .right_pane_widget .show ()
        QTimer .singleShot (10 ,lambda :self .main_splitter .setSizes ([int (self .width ()*0.3 ),int (self .width ()*0.7 )]))

        QTimer .singleShot (20 ,lambda :self .posts_content_splitter .setSizes ([int (self .posts_content_splitter .width ()*0.7 ),int (self .posts_content_splitter .width ()*0.3 )]))
        self .add_selected_button .setEnabled (False )
        self .globally_selected_post_ids .clear ()
        self .posts_search_input .setVisible (True )
        self .setWindowTitle (self ._tr ("creator_popup_title_fetching","Creator Posts"))

        self .fetch_posts_button .setEnabled (False )
        self .posts_title_list_widget .clear ()
        self .posts_date_list_widget .clear ()
        self .fetched_posts_data .clear ()
        self .posts_area_title_label .setText (self ._tr ("fav_posts_loading_status","Loading favorite posts..."))
        self .posts_title_list_widget .itemChanged .connect (self ._handle_post_item_check_changed )
        self .progress_bar .setVisible (True )

        if self .post_fetch_thread and self .post_fetch_thread .isRunning ():
            self .post_fetch_thread .cancel ()
            self .post_fetch_thread .wait ()
        print(f"[DEBUG] Starting PostsFetcherThread with creators: {selected_creators}")
        self .post_fetch_thread =PostsFetcherThread (selected_creators ,self )
        self .post_fetch_thread .status_update .connect (self ._handle_fetch_status_update )
        self .post_fetch_thread .posts_fetched_signal .connect (self ._handle_posts_fetched )
        self .post_fetch_thread .fetch_error_signal .connect (self ._handle_fetch_error )
        self .post_fetch_thread .finished_signal .connect (self ._handle_fetch_finished )
        self .post_fetch_thread .start ()

    def _tr (self ,key ,default_text =""):
        """Helper to get translation based on current app language."""
        if callable (get_translation )and self .parent_app :
            return get_translation (self .parent_app .current_selected_language ,key ,default_text )
        return default_text 

    def _retranslate_ui (self ):
        self .setWindowTitle (self ._tr ("creator_popup_title","Creator Selection"))
        self .search_input .setPlaceholderText (self ._tr ("creator_popup_search_placeholder","Search by name, service, or paste creator URL..."))
        self .add_selected_button .setText (self ._tr ("creator_popup_add_selected_button","Add Selected"))
        self .fetch_posts_button .setText (self ._tr ("fetch_posts_button_text","Fetch Posts"))
        self ._update_scope_button_text_and_tooltip ()
        self.update_button.setText(self._tr("check_for_updates_button", "Check for Updates"))

        self .posts_search_input .setPlaceholderText (self ._tr ("creator_popup_posts_search_placeholder","Search fetched posts by title..."))

        self .posts_title_header_label .setText (self ._tr ("column_header_post_title","Post Title"))
        self .posts_date_header_label .setText (self ._tr ("column_header_date_uploaded","Date Uploaded"))

        self .posts_area_title_label .setText (self ._tr ("creator_popup_posts_area_title","Fetched Posts"))
        self .posts_select_all_button .setText (self ._tr ("select_all_button_text","Select All"))
        self .posts_deselect_all_button .setText (self ._tr ("deselect_all_button_text","Deselect All"))
        self .posts_add_selected_button .setText (self ._tr ("creator_popup_add_posts_to_queue_button","Add Selected Posts to Queue"))
        self .posts_close_button .setText (self ._tr ("fav_posts_cancel_button","Cancel"))

    def _sync_scroll_dates (self ,value ):
        if not self ._is_scrolling_titles :
            self ._is_scrolling_dates =True 
            self .posts_date_list_widget .verticalScrollBar ().setValue (value )
            self ._is_scrolling_dates =False 

    def _sync_scroll_titles (self ,value ):
        if not self ._is_scrolling_dates :
            self ._is_scrolling_titles =True 
            self .posts_title_list_widget .verticalScrollBar ().setValue (value )
            self ._is_scrolling_titles =False 

    def _perform_initial_load (self ):
        """Called by QTimer to load data after dialog is shown."""
        self ._load_creators_from_json ()



    def _load_creators_from_json (self ):
        """Loads creators from creators.json and populates the list widget."""
        self .list_widget .clear ()

        self .progress_bar .setVisible (True )
        QCoreApplication .processEvents ()
        if not self .isVisible ():return 
        # Always resolve project root relative to this file
        project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../"))
        creators_file_path = os.path.join(project_root, "data", "creators.json")

        if not os .path .exists (creators_file_path ):
            self .list_widget .addItem (f"Error: creators.json not found at {creators_file_path }")
            self .all_creators_data =[]
            self .progress_bar .setVisible (False )
            QCoreApplication .processEvents ()
            return 

        try :
            with open (creators_file_path ,'r',encoding ='utf-8')as f :
                data =json .load (f )
            QCoreApplication .processEvents ()
            if not self .isVisible ():return 

            raw_data_list =[]
            if isinstance (data ,list )and len (data )>0 and isinstance (data [0 ],list ):
                raw_data_list =data [0 ]
            elif isinstance (data ,list )and all (isinstance (item ,dict )for item in data ):
                raw_data_list =data 
            else :
                self .list_widget .addItem ("Error: Invalid format in creators.json.")
                self .all_creators_data =[]
                self .progress_bar .setVisible (False );QCoreApplication .processEvents ();return 


            unique_creators_map ={}
            duplicates_skipped_count =0 
            for creator_entry in raw_data_list :
                service =creator_entry .get ('service')
                creator_id =creator_entry .get ('id')
                name_for_log =creator_entry .get ('name','Unknown')

                if service and creator_id :
                    key =(str (service ).lower ().strip (),str (creator_id ).strip ())
                    if key not in unique_creators_map :
                        unique_creators_map [key ]=creator_entry 
                    else :
                        duplicates_skipped_count +=1 
                else :
                    print (f"Warning: Creator entry in creators.json missing service or ID: {name_for_log }")

            self .all_creators_data =list (unique_creators_map .values ())
            if duplicates_skipped_count >0 :
                print (f"INFO (Creator Popup): Skipped {duplicates_skipped_count } duplicate creator entries from creators.json based on (service, id).")

            self .all_creators_data .sort (key =lambda c :(-c .get ('favorited',0 ),c .get ('name','').lower ()))
            QCoreApplication .processEvents ()
            if not self .isVisible ():return 

        except json .JSONDecodeError :
            self .list_widget .addItem ("Error: Could not parse creators.json.")
            self .all_creators_data =[]
            self .progress_bar .setVisible (False );QCoreApplication .processEvents ();return 
        except Exception as e :
            self .list_widget .addItem (f"Error loading creators: {e }")
            self .all_creators_data =[]
            self .progress_bar .setVisible (False );QCoreApplication .processEvents ();return 

        self ._filter_list ()

    def _populate_list_widget (self ,creators_to_display ):
        """Clears and populates the list widget with the given creator data."""
        self .list_widget .blockSignals (True )
        self .list_widget .clear ()

        if not creators_to_display :
            self .list_widget .blockSignals (False )






            return 

        CHUNK_SIZE_POPULATE =100 
        for i in range (0 ,len (creators_to_display ),CHUNK_SIZE_POPULATE ):
            if not self .isVisible ():
                self .list_widget .blockSignals (False )
                return 

            chunk =creators_to_display [i :i +CHUNK_SIZE_POPULATE ]
            for creator in chunk :
                creator_name_raw =creator .get ('name')
                display_creator_name =creator_name_raw .strip ()if isinstance (creator_name_raw ,str )and creator_name_raw .strip ()else "Unknown Creator"
                service_display_name =creator .get ('service','N/A').capitalize ()
                display_text =f"{display_creator_name } ({service_display_name })"
                item =QListWidgetItem (display_text )
                item .setFlags (item .flags ()|Qt .ItemIsUserCheckable )
                item .setData (Qt .UserRole ,creator )
                service =creator .get ('service')
                creator_id =creator .get ('id')
                if service is not None and creator_id is not None :
                    unique_key =(str (service ),str (creator_id ))
                    if unique_key in self .globally_selected_creators :
                        item .setCheckState (Qt .Checked )
                    else :
                        item .setCheckState (Qt .Unchecked )
                else :
                    item .setCheckState (Qt .Unchecked )
                self .list_widget .addItem (item )

            QCoreApplication .processEvents ()

        self .list_widget .blockSignals (False )

    def _filter_list (self ):
        """Filters the list widget based on the search input."""
        raw_search_input =self .search_input .text ()



        check_search_text_for_empty =raw_search_input .lower ().strip ()

        QCoreApplication .processEvents ()
        if not self .isVisible ():return 

        if not check_search_text_for_empty :
            self .progress_bar .setVisible (False )
            creators_to_show =self .all_creators_data [:self .INITIAL_LOAD_LIMIT ]
            self ._populate_list_widget (creators_to_show )
            self .search_input .setToolTip ("Search by name, service, or paste creator URL...")
            QCoreApplication .processEvents ()
        else :
            self .progress_bar .setVisible (True )
            QCoreApplication .processEvents ()
            if not self .isVisible ():return 

            norm_search_casefolded =unicodedata .normalize ('NFKC',raw_search_input ).casefold ().strip ()

            scored_matches =[]

            parsed_service_from_url ,parsed_user_id_from_url ,_ =extract_post_info (raw_search_input )

            if parsed_service_from_url and parsed_user_id_from_url :

                self .search_input .setToolTip (f"Searching for URL: {raw_search_input [:50 ]}...")
                for creator_data in self .all_creators_data :
                    creator_service_lower =creator_data .get ('service','').lower ()

                    creator_id_str_lower =str (creator_data .get ('id','')).lower ()

                    if creator_service_lower ==parsed_service_from_url .lower ()and creator_id_str_lower ==parsed_user_id_from_url .lower ():
                        scored_matches .append ((5 ,creator_data ))

                        break 

            else :


                self .search_input .setToolTip ("Searching by name or service...")
                norm_search_casefolded =unicodedata .normalize ('NFKC',raw_search_input ).casefold ().strip ()

                CHUNK_SIZE_FILTER =500 
                for i in range (0 ,len (self .all_creators_data ),CHUNK_SIZE_FILTER ):
                    if not self .isVisible ():break 
                    chunk =self .all_creators_data [i :i +CHUNK_SIZE_FILTER ]
                    for creator_data in chunk :
                        creator_name_raw =creator_data .get ('name','')
                        creator_service_raw =creator_data .get ('service','')


                        norm_creator_name_casefolded =unicodedata .normalize ('NFKC',creator_name_raw ).casefold ()
                        norm_service_casefolded =unicodedata .normalize ('NFKC',creator_service_raw ).casefold ()

                        current_score =0 

                        if norm_search_casefolded ==norm_creator_name_casefolded :
                            current_score =4 

                        elif norm_creator_name_casefolded .startswith (norm_search_casefolded ):
                            current_score =3 

                        elif norm_search_casefolded in norm_creator_name_casefolded :
                            current_score =2 

                        elif norm_search_casefolded in norm_service_casefolded :
                            current_score =1 

                        if current_score >0 :
                            scored_matches .append ((current_score ,creator_data ))

                    QCoreApplication .processEvents ()



            scored_matches .sort (key =lambda x :(-x [0 ],unicodedata .normalize ('NFKC',x [1 ].get ('name','')).casefold ()))


            final_creators_to_display =[creator_data for score ,creator_data in scored_matches [:20 ]]

            self ._populate_list_widget (final_creators_to_display )
            self .progress_bar .setVisible (False )


            if parsed_service_from_url and parsed_user_id_from_url :
                if final_creators_to_display :
                    self .search_input .setToolTip (f"Found creator by URL: {final_creators_to_display [0 ].get ('name')}")
                else :
                    self .search_input .setToolTip (f"URL parsed, but no matching creator found in your creators.json.")
            else :
                if final_creators_to_display :
                    self .search_input .setToolTip (f"Showing top {len (final_creators_to_display )} match(es) for '{raw_search_input [:30 ]}...'")
                else :
                    self .search_input .setToolTip (f"No matches found for '{raw_search_input [:30 ]}...'")

    def _toggle_scope_mode (self ):
        """Toggles the scope mode and updates the button text."""
        if self .current_scope_mode ==self .SCOPE_CHARACTERS :
            self .current_scope_mode =self .SCOPE_CREATORS 
        else :
            self .current_scope_mode =self .SCOPE_CHARACTERS 
        self ._update_scope_button_text_and_tooltip ()

    def _update_scope_button_text_and_tooltip (self ):
        if self .current_scope_mode ==self .SCOPE_CHARACTERS :
            self .scope_button .setText (self ._tr ("creator_popup_scope_characters_button","Scope: Characters"))
        else :
            self .scope_button .setText (self ._tr ("creator_popup_scope_creators_button","Scope: Creators"))

        self .scope_button .setToolTip (
        f"Current Download Scope: {self .current_scope_mode }\n\n"
        f"Click to toggle between '{self .SCOPE_CHARACTERS }' and '{self .SCOPE_CREATORS }' scopes.\n"
        f"'{self .SCOPE_CHARACTERS }': Downloads into character-named folders directly in the main Download Location (artists mixed).\n"
        f"'{self .SCOPE_CREATORS }': Downloads into artist-named subfolders within the main Download Location, then character folders inside those.")

    def _handle_fetch_status_update (self ,message ):
        if self .parent_app :
            self .parent_app .log_signal .emit (f"[CreatorPopup Fetch] {message }")
        self .posts_area_title_label .setText (message )

    def _handle_posts_fetched (self ,creator_info ,posts_list ):
        creator_key =(creator_info .get ('service'),str (creator_info .get ('id')))

        self .fetched_posts_data [creator_key ]=(creator_info ,posts_list )
        self ._filter_fetched_posts_list ()

    def _filter_fetched_posts_list (self ):
        search_text =self .posts_search_input .text ().lower ().strip ()

        data_for_rebuild ={}

        if not self .fetched_posts_data :
            self .posts_area_title_label .setText (self ._tr ("no_posts_fetched_yet_status","No posts fetched yet."))
        elif not search_text :
            data_for_rebuild =self .fetched_posts_data 

            total_posts_in_view =sum (len (posts_tuple [1 ])for posts_tuple in data_for_rebuild .values ())
            if total_posts_in_view >0 :
                self .posts_area_title_label .setText (self ._tr ("fetched_posts_count_label","Fetched {count} post(s). Select to add to queue.").format (count =total_posts_in_view ))
            else :
                self .posts_area_title_label .setText (self ._tr ("no_posts_found_for_selection","No posts found for selected creator(s)."))
        else :
            for creator_key ,(creator_data_tuple_part ,posts_list_tuple_part )in self .fetched_posts_data .items ():
                matching_posts_for_creator =[
                post for post in posts_list_tuple_part 
                if search_text in post .get ('title','').lower ()
                ]
                if matching_posts_for_creator :

                    data_for_rebuild [creator_key ]=(creator_data_tuple_part ,matching_posts_for_creator )


            total_matching_posts =sum (len (posts_tuple [1 ])for posts_tuple in data_for_rebuild .values ())
            if total_matching_posts >0 :
                self .posts_area_title_label .setText (self ._tr ("fetched_posts_count_label_filtered","Displaying {count} post(s) matching filter.").format (count =total_matching_posts ))
            else :
                self .posts_area_title_label .setText (self ._tr ("no_posts_match_search_filter","No posts match your search filter."))

        self ._rebuild_posts_list_widget (filtered_data_map =data_for_rebuild )

    def _rebuild_posts_list_widget (self ,filtered_data_map ):
        self .posts_title_list_widget .blockSignals (True )
        self .posts_date_list_widget .blockSignals (True )
        self .posts_title_list_widget .clear ()
        self .posts_date_list_widget .clear ()
        data_to_display =filtered_data_map 

        if not data_to_display :
            self .posts_title_list_widget .blockSignals (False )
            self .posts_date_list_widget .blockSignals (False )
            return 


        sorted_creator_keys =sorted (
        data_to_display .keys (),
        key =lambda k :data_to_display [k ][0 ].get ('name','').lower ()
        )

        total_posts_shown =0 
        for creator_key in sorted_creator_keys :

            creator_info_original ,posts_for_this_creator =data_to_display .get (creator_key ,(None ,[]))

            if not creator_info_original or not posts_for_this_creator :
                continue 

            creator_header_item =QListWidgetItem (f"--- {self ._tr ('posts_for_creator_header','Posts for')} {creator_info_original ['name']} ({creator_info_original ['service']}) ---")
            font =creator_header_item .font ()
            font .setBold (True )
            creator_header_item .setFont (font )
            creator_header_item .setFlags (Qt .NoItemFlags )
            self .posts_title_list_widget .addItem (creator_header_item )
            self .posts_date_list_widget .addItem (QListWidgetItem (""))

            for post in posts_for_this_creator :
                post_title =post .get ('title',self ._tr ('untitled_post_placeholder','Untitled Post'))


                date_prefix_str ="[No Date]"
                published_date_str =post .get ('published')
                added_date_str =post .get ('added')

                date_to_use_str =None 
                if published_date_str :
                    date_to_use_str =published_date_str 
                elif added_date_str :
                    date_to_use_str =added_date_str 

                if date_to_use_str :
                    try :

                        formatted_date =date_to_use_str .split ('T')[0 ]
                        date_prefix_str =f"[{formatted_date }]"
                    except Exception :
                        pass 


                date_display_str ="[No Date]"
                published_date_str =post .get ('published')
                added_date_str =post .get ('added')

                date_to_use_str =None 
                if published_date_str :
                    date_to_use_str =published_date_str 
                elif added_date_str :
                    date_to_use_str =added_date_str 

                if date_to_use_str :
                    try :

                        formatted_date =date_to_use_str .split ('T')[0 ]
                        date_display_str =f"[{formatted_date }]"
                    except Exception :
                        pass 


                title_item_text =f"  {post_title }"
                item =QListWidgetItem (title_item_text )
                item .setFlags (item .flags ()|Qt .ItemIsUserCheckable )
                item .setCheckState (Qt .Unchecked )
                item_data ={
                'title':post_title ,
                'id':post .get ('id'),
                'service':creator_info_original ['service'],
                'user_id':creator_info_original ['id'],
                'creator_name':creator_info_original ['name'],
                'full_post_data':post ,
                'date_display_str':date_display_str ,
                'published_date_for_sort':date_to_use_str 
                }
                item .setData (Qt .UserRole ,item_data )
                post_unique_key =(
                item_data ['service'],
                str (item_data ['user_id']),
                str (item_data ['id'])
                )
                if post_unique_key in self .globally_selected_post_ids :
                    item .setCheckState (Qt .Checked )
                else :
                    item .setCheckState (Qt .Unchecked )

                self .posts_title_list_widget .addItem (item )
                total_posts_shown +=1 

                date_item =QListWidgetItem (f"  {date_display_str }")
                date_item .setFlags (Qt .NoItemFlags )
                self .posts_date_list_widget .addItem (date_item )

        self .posts_title_list_widget .blockSignals (False )
        self .posts_date_list_widget .blockSignals (False )

    def _handle_fetch_error (self ,creator_info ,error_message ):
        creator_name =creator_info .get ('name','Unknown Creator')
        if self .parent_app :
            self .parent_app .log_signal .emit (f"[CreatorPopup Fetch ERROR] For {creator_name }: {error_message }")

        self .posts_area_title_label .setText (self ._tr ("fetch_error_for_creator_label","Error fetching for {creator_name}").format (creator_name =creator_name ))


    def _handle_fetch_finished (self ):
        self .fetch_posts_button .setEnabled (True )
        self .progress_bar .setVisible (False )

        if not self .fetched_posts_data :
            if self .post_fetch_thread and self .post_fetch_thread .cancellation_flag .is_set ():
                 self .posts_area_title_label .setText (self ._tr ("post_fetch_cancelled_status_done","Post fetching cancelled."))
            else :
                 self .posts_area_title_label .setText (self ._tr ("failed_to_fetch_or_no_posts_label","Failed to fetch posts or no posts found."))
            self .posts_search_input .setVisible (False )
        elif not self .posts_title_list_widget .count ()and not self .posts_search_input .text ().strip ():
            self .posts_area_title_label .setText (self ._tr ("no_posts_found_for_selection","No posts found for selected creator(s)."))
            self .posts_search_input .setVisible (True )
        else :
            QTimer .singleShot (10 ,lambda :self .posts_content_splitter .setSizes ([int (self .posts_content_splitter .width ()*0.7 ),int (self .posts_content_splitter .width ()*0.3 )]))
            self .posts_search_input .setVisible (True )

    def _handle_posts_select_all (self ):
        self .posts_title_list_widget .blockSignals (True )
        for i in range (self .posts_title_list_widget .count ()):
            item =self .posts_title_list_widget .item (i )
            if item .flags ()&Qt .ItemIsUserCheckable :
                item .setCheckState (Qt .Checked )


                item_data =item .data (Qt .UserRole )
                if item_data :
                    post_unique_key =(
                    item_data ['service'],
                    str (item_data ['user_id']),
                    str (item_data ['id'])
                    )
                    self .globally_selected_post_ids .add (post_unique_key )
        self .posts_title_list_widget .blockSignals (False )

    def _handle_posts_deselect_all (self ):
        self .posts_title_list_widget .blockSignals (True )
        for i in range (self .posts_title_list_widget .count ()):
            item =self .posts_title_list_widget .item (i )
            if item .flags ()&Qt .ItemIsUserCheckable :
                item .setCheckState (Qt .Unchecked )
        self .globally_selected_post_ids .clear ()
        self .posts_title_list_widget .blockSignals (False )

    def _handle_post_item_check_changed (self ,item ):
        if not item or not item .data (Qt .UserRole ):
            return 

        item_data =item .data (Qt .UserRole )
        post_unique_key =(
        item_data ['service'],
        str (item_data ['user_id']),
        str (item_data ['id'])
        )

        if item .checkState ()==Qt .Checked :
            self .globally_selected_post_ids .add (post_unique_key )
        else :
            self .globally_selected_post_ids .discard (post_unique_key )

    def _handle_posts_add_selected_to_queue (self ):
        selected_posts_for_queue =[]
        if not self .globally_selected_post_ids :
            QMessageBox .information (self ,self ._tr ("no_selection_title","No Selection"),
            self ._tr ("select_posts_to_queue_message","Please select at least one post to add to the queue."))
            return 

        for post_key in self .globally_selected_post_ids :
            service ,user_id_str ,post_id_str =post_key 
            post_data_found =None 
            creator_key_for_fetched_data =(service ,user_id_str )


            if creator_key_for_fetched_data in self .fetched_posts_data :
                _unused_creator_info ,posts_in_list_for_creator =self .fetched_posts_data [creator_key_for_fetched_data ]
                for post_in_list in posts_in_list_for_creator :
                    if str (post_in_list .get ('id'))==post_id_str :
                        post_data_found =post_in_list 
                        break 

            if post_data_found :

                creator_info_original ,_unused_posts =self .fetched_posts_data .get (creator_key_for_fetched_data ,({},[]))
                creator_name =creator_info_original .get ('name','Unknown Creator')if creator_info_original else 'Unknown Creator'

                domain =self ._get_domain_for_service (service )
                post_url =f"https://{domain }/{service }/user/{user_id_str }/post/{post_id_str }"
                queue_item ={
                'type':'single_post_from_popup',
                'url':post_url ,
                'name':post_data_found .get ('title',self ._tr ('untitled_post_placeholder','Untitled Post')),
                'name_for_folder':creator_name ,
                'service':service ,
                'user_id':user_id_str ,
                'post_id':post_id_str 
                }
                selected_posts_for_queue .append (queue_item )
            else :




                if self .parent_app and hasattr (self .parent_app ,'log_signal'):
                    self .parent_app .log_signal .emit (f"⚠️ Could not find full post data for selected key: {post_key } when adding to queue.")

                else :
                    domain =self ._get_domain_for_service (service )
                    post_url =f"https://{domain }/{service }/user/{user_id_str }/post/{post_id_str }"
                    queue_item ={
                    'type':'single_post_from_popup',
                    'url':post_url ,
                    'name':f"post id {post_id_str }",
                    'name_for_folder':user_id_str ,
                    'service':service ,
                    'user_id':user_id_str ,
                    'post_id':post_id_str 
                    }
                    selected_posts_for_queue .append (queue_item )

        if selected_posts_for_queue :
            if self .parent_app and hasattr (self .parent_app ,'favorite_download_queue'):
                for qi in selected_posts_for_queue :
                    self .parent_app .favorite_download_queue .append (qi )

                num_just_added_posts =len (selected_posts_for_queue )
                total_in_queue =len (self .parent_app .favorite_download_queue )

                self .parent_app .log_signal .emit (f"ℹ️ Added {num_just_added_posts } selected posts to the download queue. Total in queue: {total_in_queue }.")

                # --- START: MODIFIED LOGIC ---
                # Removed the blockSignals(True/False) calls to allow the main window's UI to update correctly.
                if self .parent_app .link_input :
                    self .parent_app .link_input .setText (
                    self .parent_app ._tr ("popup_posts_selected_text","Posts - {count} selected").format (count =num_just_added_posts )
                    )
                    self .parent_app .link_input .setPlaceholderText (
                    self .parent_app ._tr ("items_in_queue_placeholder","{count} items in queue from popup.").format (count =total_in_queue )
                    )
                # --- END: MODIFIED LOGIC ---
            
            self.selected_creators_for_queue.clear()
            
            self .accept ()
        else :
            QMessageBox .information (self ,self ._tr ("no_selection_title","No Selection"),
            self ._tr ("select_posts_to_queue_message","Please select at least one post to add to the queue."))

    def _handle_posts_close_view (self ):
        self .right_pane_widget .hide ()
        self .main_splitter .setSizes ([self .width (),0 ])
        self .posts_list_widget .itemChanged .disconnect (self ._handle_post_item_check_changed )
        if hasattr (self ,'_handle_post_item_check_changed'):
            self .posts_title_list_widget .itemChanged .disconnect (self ._handle_post_item_check_changed )
        self .posts_search_input .setVisible (False )
        self .posts_search_input .clear ()
        self .globally_selected_post_ids .clear ()
        self .add_selected_button .setEnabled (True )
        self .setWindowTitle (self ._tr ("creator_popup_title","Creator Selection"))

    def _get_domain_for_service (self ,service_name ):
        """Determines the base domain for a given service."""
        service_lower =service_name .lower ()
        if service_lower in ['onlyfans','fansly']:
            return "coomer.su"
        return "kemono.su"

    def _handle_add_selected (self ):
        """Gathers globally selected creators and processes them."""
        selected_display_names =[]
        self .selected_creators_for_queue .clear ()
        for creator_data in self .globally_selected_creators .values ():
            creator_name =creator_data .get ('name')
            self .selected_creators_for_queue .append (creator_data )
            if creator_name :
                selected_display_names .append (creator_name )

        if selected_display_names :
            main_app_window =self .parent ()
            if hasattr (main_app_window ,'link_input'):
                main_app_window .link_input .setText (", ".join (selected_display_names ))
            self .accept ()
        else :
            QMessageBox .information (self ,"No Selection","No creators selected to add.")

    def _handle_item_check_changed (self ,item ):
        """Updates the globally_selected_creators dict when an item's check state changes."""
        creator_data =item .data (Qt .UserRole )
        if not isinstance (creator_data ,dict ):
            return 

        service =creator_data .get ('service')
        creator_id =creator_data .get ('id')

        if service is None or creator_id is None :
            print (f"Warning: Creator data in list item missing service or id: {creator_data .get ('name')}")
            return 

        unique_key =(str (service ),str (creator_id ))

        if item .checkState ()==Qt .Checked :
            self .globally_selected_creators [unique_key ]=creator_data 
        else :
            if unique_key in self .globally_selected_creators :
                del self .globally_selected_creators [unique_key ]
        self .fetch_posts_button .setEnabled (bool (self .globally_selected_creators ))