#!/usr/bin/env python3
# Copyright (C) 2023 Stefy Lanza <stefy@nexlab.net> and SexHack.me
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

import argparse
import os
import sys
import signal
import threading
import webbrowser
import logging
from logging.handlers import RotatingFileHandler
import socket
import configparser

from flask import Flask, render_template, request
import subprocess
import tkinter as tk
from tkinter import font as tkFont
import vlc

# Read configuration
config = configparser.ConfigParser()
config.read('config.ini')

# Setup logging
log_file = config.get('General', 'log_file', fallback='/tmp/streaming_control.log')
log_level = config.get('General', 'log_level', fallback='INFO')

logging.basicConfig(
    level=getattr(logging, log_level),
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        RotatingFileHandler(log_file, maxBytes=1024*1024, backupCount=5),
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger(__name__)

# Flask App Setup
flask_app = Flask(__name__)

# Command Mapping
COMMANDS = dict(config['Commands'])

def run_command(command):
    try:
        result = subprocess.run(command, shell=True, check=True, 
                                capture_output=True, text=True)
        logger.info(f"Command executed: {command}")
        return result.stdout
    except subprocess.CalledProcessError as e:
        logger.error(f"Error executing command {command}: {e}")
        return f"Error: {e}"

@flask_app.route('/')
def index():
    return render_template('index.html', commands=COMMANDS)

@flask_app.route('/execute', methods=['POST'])
def execute():
    command_key = request.form.get('command')
    
    if command_key in COMMANDS:
        result = run_command(COMMANDS[command_key])
        return result
    else:
        return "Invalid command", 400

@flask_app.route('/stream')
def stream():
    stream_url = config.get('Web', 'stream_url', fallback="https://192.168.42.1/HLS/record/Live.m3u8")
    return render_template('stream.html', stream_url=stream_url)

def create_daemon():
    if os.name == 'posix':  # Unix-like systems
        try:
            # First fork
            pid = os.fork()
            if pid > 0:
                # Exit first parent
                sys.exit(0)
        except OSError as err:
            logger.error(f'Fork #1 failed: {err}')
            sys.exit(1)
        
        # Decouple from parent environment
        os.chdir('/')
        os.setsid()
        os.umask(0)
        
        # Second fork
        try:
            pid = os.fork()
            if pid > 0:
                # Exit from second parent
                sys.exit(0)
        except OSError as err:
            logger.error(f'Fork #2 failed: {err}')
            sys.exit(1)
        
        # Redirect standard file descriptors
        sys.stdout.flush()
        sys.stderr.flush()
        si = open(os.devnull, 'r')
        so = open(os.devnull, 'a+')
        se = open(os.devnull, 'a+')
        os.dup2(si.fileno(), sys.stdin.fileno())
        os.dup2(so.fileno(), sys.stdout.fileno())
        os.dup2(se.fileno(), sys.stderr.fileno())
    
    elif os.name == 'nt':  # Windows
        try:
            # Hide the console window
            si = subprocess.STARTUPINFO()
            si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            
            # Start the script as a new process
            subprocess.Popen([sys.executable, __file__], 
                             startupinfo=si, 
                             creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
            
            # Exit the current process
            sys.exit(0)
        except Exception as err:
            logger.error(f'Failed to create background process: {err}')
            sys.exit(1)
    
    else:
        logger.error(f'Unsupported operating system: {os.name}')
        sys.exit(1)

def check_port_available(port):
    """Check if a port is available"""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        return s.connect_ex(('localhost', port)) != 0

def run_flask_app(port=5000, daemon_mode=False):
    """Run Flask app with optional daemon mode"""
    if not check_port_available(port):
        logger.error(f"Port {port} is already in use")
        sys.exit(1)

    logger.info(f"Starting Flask app on port {port}")
    
    if daemon_mode and sys.platform != 'win32':
        create_daemon()
    
    flask_app.run(host='0.0.0.0', port=port, debug=False, use_reloader=False)

class VideoPlayer:
    def __init__(self, master, video_url):
        self.master = master
       
        # VLC player setup
        args = []
        _isLinux = sys.platform.startswith('linux')
        if _isLinux:
            args.append('--vout=mmal_vout') 

        # Create a VLC instance
        self.Instance = vlc.Instance(args)
        
        # Create a new MediaPlayer
        self.player = self.Instance.media_player_new()
        
        # Set the media
        media = self.Instance.media_new(video_url)
        self.player.set_media(media)
        
        # Create a frame for the video
        self.video_frame = self.master
        self.video_frame.pack(fill=tk.BOTH, expand=True)
        self.canvas = tk.Canvas(self.video_frame, width=800)
        self.canvas.pack(fill=tk.BOTH, expand=True)

        # Embed the VLC Video
        win_id = self.canvas.winfo_id()
        if _isLinux:
            self.player.set_xwindow(win_id)
        else:
            self.player.set_hwnd(win_id)
       
        # Play the video
        self.player.play()



def create_tkinter_gui():
    # Create the main window
    window = tk.Tk()
    window.title("Streaming Control Panel")

    helv36 = tkFont.Font(family='Helvetica', size=13, weight='bold')

    # Frame for the left side
    fleft = tk.Frame(window)
    fleft.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

    # URL of your HLS stream
    video_url = "rtmp://192.168.42.1/record/Live"
    VideoPlayer(fleft, video_url)

    # Frame for the right side
    fright = tk.Frame(window)
    fright.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

    # Frame for the first two rows in the right frame
    frame1 = tk.Frame(fright)
    frame1.pack(fill=tk.BOTH, expand=True)

    # Buttons configuration
    buttons_row0 = [
        ('PRIVATE STEFY', 'smblur_private_stefy'),
        ('PRIVATE LEELOO', 'smblur_private_leeloo'),
        ('PRIVATE JASMIN', 'smblur_private_jasmin'),
        ('PRIVATE OTHER', 'smblur_private')
    ]

    buttons_row1 = [
        ('OPEN/CLOSE STEFY', 'smblur_stefy'),
        ('OPEN/CLOSE LEELOO', 'smblur_leeloo'),
        ('OPEN/CLOSE JASMIN', 'smblur_jasmin'),
        ('OPEN/CLOSE OTHERS', 'smblur_shine')
    ]

    # Create buttons for the first two rows
    for j, (text, command) in enumerate(buttons_row0):
        button = tk.Button(frame1, text=text, font=helv36, width=25, height=15, bg="green", fg="white", 
                           command=lambda cmd=command: run_command(cmd))
        button.grid(row=0, column=j, sticky='nsew')

    for j, (text, command) in enumerate(buttons_row1):
        button = tk.Button(frame1, text=text, font=helv36, width=25, height=15, bg="green", fg="white", 
                           command=lambda cmd=command: run_command(cmd))
        button.grid(row=1, column=j, sticky='nsew')

    # Configure the columns in the first frame
    for i in range(4):
        frame1.grid_columnconfigure(i, weight=1)

    # Frame for the third row in the right frame
    frame2 = tk.Frame(fright)
    frame2.pack(fill=tk.BOTH, expand=True)

    # Row 2 with 3 buttons
    buttons_row2 = [
        ('TEASE', 'smblur_tease'),
        ('TEASE ALL', 'smblur_teaseall'),
        ('OPEN', 'smblur_clean')
    ]

    # Create buttons for the third row
    for j, (text, command) in enumerate(buttons_row2):
        button = tk.Button(frame2, text=text, font=helv36, width=30, height=25, bg="blue", fg="white", 
                           command=lambda cmd=command: run_command(cmd))
        button.grid(row=0, column=j, sticky='nsew')

    # Configure the columns in the second frame
    for i in range(3):
        frame2.grid_columnconfigure(i, weight=1)

    # Add a button to open web interface
    web_button = tk.Button(frame2, text="Open Web Interface", 
                            command=lambda: webbrowser.open('http://localhost:5000'), 
                            bg="purple", fg="white", font=helv36)
    web_button.grid(row=1, column=1, sticky='nsew')

    return window

def main():
    # Setup argument parser
    parser = argparse.ArgumentParser(description='Streaming Control Panel')
    parser.add_argument('--web-only', action='store_true', 
                        help='Start only the web interface')
    parser.add_argument('--daemon', action='store_true', 
                        help='Run in daemon mode (Unix-like systems only)')
    parser.add_argument('--port', type=int, default=5000, 
                        help='Port for the web interface (default: 5000)')
    
    # Parse arguments
    args = parser.parse_args()

    try:
        # Daemon mode for web interface
        if args.web_only or args.daemon:
            run_flask_app(port=args.port, daemon_mode=args.daemon)
        else:
            # Start web interface in a background thread
            web_thread = threading.Thread(
                target=run_flask_app, 
                kwargs={'port': args.port}, 
                daemon=True
            )
            web_thread.start()

            # Launch Tkinter GUI
            window = create_tkinter_gui()
            window.mainloop()

    except Exception as e:
        logger.error(f"Unexpected error: {e}")
        sys.exit(1)

if __name__ == '__main__':
    main()
