from textual.containers import Vertical, VerticalScroll, Horizontal, VerticalGroup, HorizontalGroup
from textual.widgets import Rule
from textual.app import ComposeResult
from textual import on, events

from ui.widgets.chunk_types.audio import AudioChunk, Chunk
from ui.widgets.play_head import PlayHead
from project import ChunkType

from song_player import SongPlayer


class TimelineRow(Horizontal):
    DEFAULT_CSS = """
    TimelineRow {
        background: $surface-lighten-1;
        height: 8;
        margin-bottom: 1;
        
        &.-muted {
            background: $error 25%;
        }
        
        &.-solo {
            background: $warning 25%;
        }
    }
    """
    
    def __init__(self, project_channel):
        super().__init__()
        self.project_channel = project_channel

class Timeline(Vertical):
    DEFAULT_CSS = """
    Timeline {
        overflow-x: auto;
        
        #rows {
            hatch: "-" $surface-lighten-1;
            padding: 0 0;
            
            
            
            .beat-line {
                color: $surface-lighten-1;
                
            }
            
            .bar-line {
                color: $surface-lighten-2;
                
            }
            
            .beat-line, .bar-line {
                dock: left;
                margin: 0;
            }
            
            
        }
        
        PlayHead {
            layer: top;
        }
    }
    """
    
    def __init__(self):
        super().__init__(id="timeline")
        
        self.calc_bar_offset()
        self.song_player = SongPlayer(self, self.app.project)
        
    def calc_bar_offset(self):
        self.bar_offset = self.app.project.bpm / 8 * (0.03333333333 / self.app.zoom_level)
        
        for row in self.query(TimelineRow):
            row.styles.width = self.bar_offset * self.app.project.song_length
        
    @on(events.MouseScrollDown)
    async def mouse_scroll_down(self, event: events.MouseScrollDown):
        self.app.zoom_level += (self.app.scroll_sensitivity_x / 200)
        self.calc_bar_offset()
        self.app.last_zoom_level = self.app.zoom_level
        await self.handle_zoom()
        
    @on(events.MouseScrollUp)
    async def mouse_scroll_up(self, event: events.MouseScrollUp):
        self.app.zoom_level = max(self.app.zoom_level - self.app.scroll_sensitivity_x/200, 0.001)
        
        if self.app.zoom_level != self.app.last_zoom_level:
            self.app.last_zoom_level = self.app.zoom_level
            self.calc_bar_offset()
            await self.handle_zoom()
            
    @on(events.MouseDown)
    async def mouse_down(self, event: events.MouseDown):
        if event.button != 2: return
        
        # get bar number
        bar_number = event.x / self.bar_offset
        
        # convert bar number to seconds
        seconds = bar_number / self.app.project.seconds_per_bar
        
        # seek to number of seconds
        self.song_player.seek(seconds)
            
    async def handle_zoom(self):
        for chunk in self.query(Chunk):
            chunk.calculate_size()
            chunk.update_offset(self)
            
        for bar_line in self.query(Rule):
            if not isinstance(bar_line, PlayHead):
                bar_line.offset = (self.bar_offset * bar_line.index, 0)
                
                if self.app.zoom_level >= 0.09 and bar_line.has_class("beat-line"):
                    bar_line.display = False
                else:
                    if self.app.zoom_level < 0.18:
                        bar_line.display = True
                    else:
                        if bar_line.has_class("bar-line") and bar_line.index % 16 == 0:
                            bar_line.display = True
                        else:
                            bar_line.display = False
        
        if self.song_player.paused and self.song_player.project:
            await self.song_player.update_visual_playhead()
    
    def compose(self) -> ComposeResult:
        
        
        
        with VerticalScroll(id="rows"):
            for channel in self.app.project.channels:
                with TimelineRow(channel) as row:
                    
                    row.styles.width = self.bar_offset * self.app.project.song_length

                    for chunk in channel.chunks:
                        
                        if chunk.chunk_type == ChunkType.CHUNK:
                            yield Chunk(chunk_name=chunk.name, bar_pos=chunk.position)
                        elif chunk.chunk_type == ChunkType.AUDIO:
                            yield AudioChunk(chunk.audio_data, chunk.sample_rate, chunk.name, chunk.position)

            for i in range(1, self.app.project.song_length+1):
                bar = None
                if i % 4 == 0:
                    bar = Rule.vertical(classes="bar-line", line_style="double")
                else:
                    bar = Rule.vertical(classes="beat-line")
                    
                bar.offset = (self.bar_offset * i, 0)
                bar.index = i
                    
                yield bar
             
        
             
        yield PlayHead()