import click

from textual.screen import Screen
from textual.widgets import Header, Footer, Static, Button, DataTable, Input, TextArea
from textual.containers import Grid
from textual.widgets._data_table import CellDoesNotExist

from .pattern_details_screen import PatternDetailsScreen
from .pattern_delete_screen import PatternDeleteScreen

from .show_descriptor import ShowDescriptor

from .shifted_season_details_screen import ShiftedSeasonDetailsScreen
from .shifted_season_delete_screen import ShiftedSeasonDeleteScreen

from ffx.model.shifted_season import ShiftedSeason

from .helper import filterFilename
from .screen_support import build_screen_bootstrap, build_screen_controllers


# Screen[dict[int, str, int]]
class ShowDetailsScreen(Screen):

    CSS = """

    Grid {
        grid-size: 5 18;
        grid-rows: 2 2 2 2 2 2 6 2 2 2 2 2 2 9 2 9 2 2;
        grid-columns: 30 30 30 30 30;
        height: 100%;
        width: 100%;
        padding: 1;
    }

    Input {
        border: none;
    }
    Button {
        border: none;
    }

    DataTable {
        column-span: 2;
        min-height: 8;
    }

    DataTable .datatable--cursor {
        background: darkorange;
        color: black;
    }

    DataTable .datatable--header {
        background: steelblue;
        color: white;
    }

    #toplabel {
        height: 1;
    }


    .two {
        column-span: 2;
    }
    .three {
        column-span: 3;
    }
    .four {
        column-span: 4;
    }
    .five {
        column-span: 5;
    }

    .box {
        height: 100%;
        border: solid green;
    }

    .note_box {
        min-height: 6;
    }
    """

    BINDINGS = [
        ("a", "add_pattern", "Add Pattern"),
        ("e", "edit_pattern", "Edit Pattern"),
        ("r", "remove_pattern", "Remove Pattern"),
    ]

    def __init__(self, showId = None):
        super().__init__()

        bootstrap = build_screen_bootstrap(self.app.getContext())
        self.context = bootstrap.context

        controllers = build_screen_controllers(
            self.context,
            pattern=True,
            show=True,
            tmdb=True,
            shifted_season=True,
        )
        self.__sc = controllers['show']
        self.__pc = controllers['pattern']
        self.__tc = controllers['tmdb']
        self.__ssc = controllers['shifted_season']

        self.__showDescriptor = self.__sc.getShowDescriptor(showId) if showId is not None else None



    def updateShiftedSeasons(self):

        self.shiftedSeasonsTable.clear()

        if not self.__showDescriptor is None:

            showId = int(self.__showDescriptor.getId())

            shiftedSeason: ShiftedSeason
            for shiftedSeason in self.__ssc.getShiftedSeasonSiblings(showId=showId):

                shiftedSeasonObj = shiftedSeason.getObj()

                firstEpisode = shiftedSeasonObj['first_episode']
                firstEpisodeStr = str(firstEpisode) if firstEpisode != -1 else ''
                
                lastEpisode = shiftedSeasonObj['last_episode']
                lastEpisodeStr = str(lastEpisode) if lastEpisode != -1 else ''

                row = (shiftedSeasonObj['original_season'],
                        firstEpisodeStr,
                        lastEpisodeStr,
                        shiftedSeasonObj['season_offset'],
                        shiftedSeasonObj['episode_offset'])

                self.shiftedSeasonsTable.add_row(*map(str, row))



    def on_mount(self):

        if self.__showDescriptor is not None:

            showId = int(self.__showDescriptor.getId())

            self.query_one("#id_static", Static).update(str(showId))
            self.query_one("#name_input", Input).value = str(self.__showDescriptor.getName())
            self.query_one("#year_input", Input).value = str(self.__showDescriptor.getYear())

            self.query_one("#index_season_digits_input", Input).value = str(self.__showDescriptor.getIndexSeasonDigits())
            self.query_one("#index_episode_digits_input", Input).value = str(self.__showDescriptor.getIndexEpisodeDigits())
            self.query_one("#indicator_season_digits_input", Input).value = str(self.__showDescriptor.getIndicatorSeasonDigits())
            self.query_one("#indicator_episode_digits_input", Input).value = str(self.__showDescriptor.getIndicatorEpisodeDigits())
            if self.__showDescriptor.getQuality():
                self.query_one("#quality_input", Input).value = str(self.__showDescriptor.getQuality())
            if self.__showDescriptor.getNotes():
                self.query_one("#notes_textarea", TextArea).text = str(self.__showDescriptor.getNotes())

            
            #raise click.ClickException(f"show_id {showId}")
            for pattern in self.__pc.getPatternsForShow(showId):
                row = (pattern.getPattern(),)
                self.patternTable.add_row(*map(str, row))

            self.updateShiftedSeasons()

        else:
            defaultDigitLengths = ShowDescriptor.getDefaultDigitLengths(self.context)

            self.query_one("#index_season_digits_input", Input).value = str(
                defaultDigitLengths[ShowDescriptor.INDEX_SEASON_DIGITS_KEY]
            )
            self.query_one("#index_episode_digits_input", Input).value = str(
                defaultDigitLengths[ShowDescriptor.INDEX_EPISODE_DIGITS_KEY]
            )
            self.query_one("#indicator_season_digits_input", Input).value = str(
                defaultDigitLengths[ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY]
            )
            self.query_one("#indicator_episode_digits_input", Input).value = str(
                defaultDigitLengths[ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY]
            )


    def getSelectedPatternDescriptor(self):

        selectedPattern = {}

        try:

            # Fetch the currently selected row when 'Enter' is pressed
            #selected_row_index = self.table.cursor_row
            row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)

            if row_key is not None:
                selected_row_data = self.patternTable.get_row(row_key)

                selectedPattern['show_id'] = self.__showDescriptor.getId()
                selectedPattern['pattern'] = str(selected_row_data[0])

        except CellDoesNotExist:
            pass

        return selectedPattern


    def getSelectedShiftedSeasonObjFromInput(self):

        shiftedSeasonObj = {}

        try:

            # Fetch the currently selected row when 'Enter' is pressed
            #selected_row_index = self.table.cursor_row
            row_key, col_key = self.shiftedSeasonsTable.coordinate_to_cell_key(self.shiftedSeasonsTable.cursor_coordinate)

            if row_key is not None:
                selected_row_data = self.shiftedSeasonsTable.get_row(row_key)

                def parse_int_or_default(value: str, default: int) -> int:
                    try:
                        return int(value)
                    except (TypeError, ValueError):
                        return default

                shiftedSeasonObj['original_season'] = int(selected_row_data[0])
                shiftedSeasonObj['first_episode'] = parse_int_or_default(selected_row_data[1], -1)
                shiftedSeasonObj['last_episode'] = parse_int_or_default(selected_row_data[2], -1)
                shiftedSeasonObj['season_offset'] = parse_int_or_default(selected_row_data[3], 0)
                shiftedSeasonObj['episode_offset'] = parse_int_or_default(selected_row_data[4], 0)


                if self.__showDescriptor is not None:

                    showId = int(self.__showDescriptor.getId())

                    shiftedSeasonId = self.__ssc.findShiftedSeason(showId,
                                                                    originalSeason=shiftedSeasonObj['original_season'],
                                                                    firstEpisode=shiftedSeasonObj['first_episode'],
                                                                    lastEpisode=shiftedSeasonObj['last_episode'])
                    if shiftedSeasonId is not None:
                        shiftedSeasonObj['id'] = shiftedSeasonId

        except CellDoesNotExist:
            pass

        return shiftedSeasonObj


    def action_add_pattern(self):
        if not self.__showDescriptor is None:
            self.app.push_screen(PatternDetailsScreen(showId = self.__showDescriptor.getId()), self.handle_add_pattern)


    def handle_add_pattern(self, screenResult):

        pattern = (screenResult['pattern'],)
        self.patternTable.add_row(*map(str, pattern))


    def action_edit_pattern(self):
            
        selectedPatternDescriptor = self.getSelectedPatternDescriptor()

        if selectedPatternDescriptor:

            selectedPatternId = self.__pc.findPattern(selectedPatternDescriptor)
            
            if selectedPatternId is None:
                raise click.ClickException(f"ShowDetailsScreen.action_edit_pattern(): Pattern to edit has no id")

            self.app.push_screen(PatternDetailsScreen(patternId = selectedPatternId, showId = self.__showDescriptor.getId()), self.handle_edit_pattern) # <-


    def handle_edit_pattern(self, screenResult):

        try:        

            row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
            self.patternTable.update_cell(row_key, self.column_key_pattern, screenResult['pattern'])

        except CellDoesNotExist:
            pass


    def action_remove_pattern(self):
            
        selectedPatternDescriptor = self.getSelectedPatternDescriptor()

        if selectedPatternDescriptor:
            
            selectedPatternId = self.__pc.findPattern(selectedPatternDescriptor)
            
            if selectedPatternId is None:
                raise click.ClickException(f"ShowDetailsScreen.action_remove_pattern(): Pattern to remove has no id")

            self.app.push_screen(PatternDeleteScreen(patternId = selectedPatternId, showId = self.__showDescriptor.getId()), self.handle_remove_pattern)


    def handle_remove_pattern(self, pattern):

        try:
            row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
            self.patternTable.remove_row(row_key)

        except CellDoesNotExist:
            pass


    def compose(self):

        # Create the DataTable widget
        self.patternTable = DataTable(classes="five")

        # Define the columns with headers
        self.column_key_pattern = self.patternTable.add_column("Pattern", width=150)

        self.patternTable.cursor_type = 'row'


        self.shiftedSeasonsTable = DataTable(classes="five")

        self.column_key_original_season = self.shiftedSeasonsTable.add_column("Source Season", width=30)
        self.column_key_first_episode = self.shiftedSeasonsTable.add_column("First Episode", width=30)
        self.column_key_last_episode = self.shiftedSeasonsTable.add_column("Last Episode", width=30)
        self.column_key_season_offset = self.shiftedSeasonsTable.add_column("Season Offset", width=30)
        self.column_key_episode_offset = self.shiftedSeasonsTable.add_column("Episode Offset", width=30)

        self.shiftedSeasonsTable.cursor_type = 'row'


        yield Header()

        with Grid():

            # 1
            yield Static("Show" if not self.__showDescriptor is None else "New Show", id="toplabel")
            yield Button("Identify", id="identify_button")
            yield Static(" ", classes="three")

            # 2
            yield Static("ID")
            if not self.__showDescriptor is None:
                yield Static("", id="id_static", classes="four")
            else:
                yield Input(type="integer", id="id_input", classes="four")
            
            # 3
            yield Static("Name")
            yield Input(type="text", id="name_input", classes="four")

            # 4
            yield Static("Year")
            yield Input(type="integer", id="year_input", classes="four")

            #5
            yield Static("Quality")
            yield Input(type="integer", id="quality_input", classes="four")

            #6
            yield Static("Notes")
            yield Static(" ", classes="four")

            #7
            yield TextArea(id="notes_textarea", classes="five note_box")

            #8
            yield Static("Index Season Digits")
            yield Input(type="integer", id="index_season_digits_input", classes="four")

            #9
            yield Static("Index Episode Digits")
            yield Input(type="integer", id="index_episode_digits_input", classes="four")

            #10
            yield Static("Indicator Season Digits")
            yield Input(type="integer", id="indicator_season_digits_input", classes="four")

            #11
            yield Static("Indicator Edisode Digits")
            yield Input(type="integer", id="indicator_episode_digits_input", classes="four")

            # 12
            yield Static(" ", classes="five")

            # 13
            yield Static("Shifted seasons", classes="two")

            if self.__showDescriptor is not None:
                yield Button("Add", id="button_add_shifted_season")
                yield Button("Edit", id="button_edit_shifted_season")
                yield Button("Delete", id="button_delete_shifted_season")
            else:
                yield Static(" ")
                yield Static(" ")
                yield Static(" ")

            # 14
            yield self.shiftedSeasonsTable

            # 15
            yield Static("File patterns", classes="five")
            # 16
            yield self.patternTable

            # 17
            yield Static(" ", classes="five")

            # 18
            yield Button("Save", id="save_button")
            yield Button("Cancel", id="cancel_button")


        yield Footer()


    def getShowDescriptorFromInput(self) -> ShowDescriptor:

        kwargs = {ShowDescriptor.CONTEXT_KEY: self.context}
        
        try:
            if self.__showDescriptor:
                kwargs[ShowDescriptor.ID_KEY] = int(self.__showDescriptor.getId())
            else:
                kwargs[ShowDescriptor.ID_KEY] = int(self.query_one("#id_input", Input).value)
        except ValueError:
            return None

        try:    
            kwargs[ShowDescriptor.NAME_KEY] = str(self.query_one("#name_input", Input).value)
        except ValueError:
            pass
        try:
            kwargs[ShowDescriptor.YEAR_KEY] = int(self.query_one("#year_input", Input).value)
        except ValueError:
            pass

        try:
            kwargs[ShowDescriptor.INDEX_SEASON_DIGITS_KEY] = int(self.query_one("#index_season_digits_input", Input).value)
        except ValueError:
            pass
            
        try:
            kwargs[ShowDescriptor.INDEX_EPISODE_DIGITS_KEY] = int(self.query_one("#index_episode_digits_input", Input).value)
        except ValueError:
            pass
        try:
            kwargs[ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY] = int(self.query_one("#indicator_season_digits_input", Input).value)
        except ValueError:
            pass
        try:
            kwargs[ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY] = int(self.query_one("#indicator_episode_digits_input", Input).value)
        except ValueError:
            pass
        try:
            kwargs[ShowDescriptor.QUALITY_KEY] = int(self.query_one("#quality_input", Input).value)
        except ValueError:
            pass
        kwargs[ShowDescriptor.NOTES_KEY] = str(self.query_one("#notes_textarea", TextArea).text)

        return ShowDescriptor(**kwargs)


   # Event handler for button press
    def on_button_pressed(self, event: Button.Pressed) -> None:

        if event.button.id == "save_button":

            showDescriptor = self.getShowDescriptorFromInput()

            if not showDescriptor is None:
                if self.__sc.updateShow(showDescriptor):
                    self.dismiss(showDescriptor)
                else:
                    #TODO: Meldung
                    self.app.pop_screen()

        if event.button.id == "cancel_button":
            self.app.pop_screen()


        if event.button.id == "identify_button":

            showDescriptor = self.getShowDescriptorFromInput()
            if not showDescriptor is None:
                showName, showYear = self.__tc.getShowNameAndYear(showDescriptor.getId())

                self.query_one("#name_input", Input).value = filterFilename(showName)
                self.query_one("#year_input", Input).value = str(showYear)


        if event.button.id == "button_add_shifted_season":
            if not self.__showDescriptor is None:
                self.app.push_screen(ShiftedSeasonDetailsScreen(showId = self.__showDescriptor.getId()), self.handle_update_shifted_season)

        if event.button.id == "button_edit_shifted_season":
            selectedShiftedSeasonObj = self.getSelectedShiftedSeasonObjFromInput()
            if 'id' in selectedShiftedSeasonObj.keys():
                self.app.push_screen(ShiftedSeasonDetailsScreen(showId = self.__showDescriptor.getId(), shiftedSeasonId=selectedShiftedSeasonObj['id']), self.handle_update_shifted_season)

        if event.button.id == "button_delete_shifted_season":
            selectedShiftedSeasonObj = self.getSelectedShiftedSeasonObjFromInput()
            if 'id' in selectedShiftedSeasonObj.keys():
                self.app.push_screen(ShiftedSeasonDeleteScreen(showId = self.__showDescriptor.getId(), shiftedSeasonId=selectedShiftedSeasonObj['id']), self.handle_delete_shifted_season)


    def handle_update_shifted_season(self, screenResult):
        self.updateShiftedSeasons()

    def handle_delete_shifted_season(self, screenResult):
        self.updateShiftedSeasons()
