#!/usr/bin/env python3

import subprocess

import json

import os

import csv

# ffmpeg wrapper
import ffmpy

# argument parsing
import argparse


def valid_duration(filename: str, filetype: str):
    """
    Check given file for presence of duration metadata

    Parameters:
    filename (str): Path to file
    filetype (str): Should be INPUT or OUTPUT, to define if the issue appeared after encoding or before
    """
    # NOTE check all files for an intact/valid duration
    # Valid file example output:
    # {
    #     "format": {
    #         "duration": "1425.058000"
    #     }
    # }
    # Invalid file:
    # {
    #     "format": {
    #
    #     }
    # }
    ff = ffmpy.FFprobe(
        inputs={filename: None},
        global_options=("-show_entries format=duration -v quiet -print_format json"),
    )

    proc = subprocess.Popen(
        ff.cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True
    )

    info = json.loads(proc.stdout.read().rstrip().decode("utf8"))

    # write broken files to error.csv files in current directory
    if "duration" not in info["format"]:
        with open("error.csv", "a", newline="") as file:
            write = csv.writer(file)
            write.writerow((filetype, filename))


parser = argparse.ArgumentParser(description="")

# Input file
parser.add_argument("-i", "--input-file", required=True, type=str, help="Input file")

# Media title
parser.add_argument("-t", "--title", required=True, type=str, help="Media title")

# Video stuff
parser.add_argument(
    "-vc",
    "--video-codec",
    required=False,
    type=str,
    help="Output video codec. Defaults to 'copy'",
)
parser.add_argument(
    "-crf",
    "--crf",
    required=False,
    type=int,
    help="Codec crf. No effect if video codec is 'copy'. Defaults to 20",
)
parser.add_argument(
    "-vt", "--video-tune", required=False, type=str, help="Video codec tune"
)
parser.add_argument(
    "-vp",
    "--video-preset",
    required=False,
    type=str,
    help="Video compression preset. Defaults to 'medium'",
)

# Audio stuff
parser.add_argument(
    "-ac",
    "--audio-codec",
    required=False,
    type=str,
    help="Output audio codec. Defaults to 'copy'",
)
parser.add_argument(
    "-ab",
    "--audio-bitrate",
    required=False,
    type=str,
    help="Output audio bitrate. No effect if audio codec is 'copy'. Defaults to '192k'",
)
parser.add_argument(
    "-aj",
    "--audio-japanese",
    required=False,
    type=str,
    help="Stream identifier for japanese audio",
)
parser.add_argument(
    "-ae",
    "--audio-english",
    required=False,
    type=str,
    help="Stream identifier for english audio",
)

# Subtitle stuff
parser.add_argument(
    "-sn", "--subtitle-name", required=False, type=str, help="Name for subtitles"
)
parser.add_argument(
    "-si",
    "--subtitle-stream",
    required=False,
    type=str,
    help="Stream identifier for subtitles",
)

"""
parser.add_argument(
    "-sd",
    "--set-default-subtitle",
    required=False,
    action="store_true",
    help="If passed, set the first subtitle as default",
)
"""

# Output file
parser.add_argument("-o", "--output-file", required=True, type=str, help="Output file")

"""
# Execute or print commands
parser.add_argument(
    "-e",
    "--execute",
    action="store_true",
    help="Execute script. If not set, shows the commands that would be run.",
)
"""

args = parser.parse_args()

title = args.title

inputfile = args.input_file

# Default video codec is copy
if args.video_codec is None:
    videocodec = "copy"
else:
    videocodec = args.video_codec

# Default crf of 20
if args.crf is None:
    crf = 20
else:
    crf = args.crf

if args.video_tune is None:
    tune = ""
else:
    tune = "-tune " + args.video_tune

if args.video_preset is None:
    preset = "medium"
else:
    preset = args.video_preset

# Default audio codec is copy
if args.audio_codec is None:
    audiocodec = "copy"
else:
    audiocodec = args.audio_codec

# Default audio codec is copy
if args.audio_bitrate is None:
    audiobitrate = "192k"
else:
    audiobitrate = args.audio_bitrate

outputfile = args.output_file

# Map japanese audio, if set
if args.audio_japanese is None:
    japaneseaudio = ""
else:
    japaneseaudio = "-map " + args.audio_japanese

# Map english audio, if set
if args.audio_english is None:
    englishaudio = ""
else:
    englishaudio = "-map " + args.audio_english

# Audiometadata
if args.audio_japanese is None:
    audiometa = "-metadata:s:a:0 title='English' -metadata:s:a:0 language=eng"
else:
    audiometa = "-metadata:s:a:0 title='Japanese' -metadata:s:a:0 language=jpn -metadata:s:a:1 title='English' -metadata:s:a:1 language=eng"

subtitle = args.subtitle_name
subtitlestream = args.subtitle_stream

"""
if args.set_default_subtitle:
    defaultsub = "-disposition:s:0 default"
else:
    defaultsub = ""
"""
defaultsub = "-disposition:s:0 default"

"""
# Flag to actually execute command
execute = args.execute
"""
execute = True

# check input file for valid duration
valid_duration(inputfile, "INPUT")

# FIXME Breaks if any field (filename, title, Language) contains quotes: '
# Maps the first video stream, selected audio streams, selected subtitle streams and any attachments to the remuxed/reencoded video
ff = ffmpy.FFmpeg(
    inputs={inputfile: None},
    outputs={
        outputfile: "-metadata title='{title}' -disposition 0 -map 0:t?"
        " "
        "-c:v {videocodec} -crf {crf} {tune} -preset {preset} -map 0:v:0 -metadata:s:v:0 title='Video' -disposition:v:0 default"
        " "
        "-c:a {audiocodec} -b:a {audiobitrate} {jpnaudiomap} {engaudiomap}"
        " "
        "{audiometa} -disposition:a:0 default"
        " "
        "-c:s copy -map {substream}? -metadata:s:s:0 title='{subtitle}' -metadata:s:s:0 language=eng {defaultsub}"
        " ".format(
            title=title,
            videocodec=videocodec,
            crf=crf,
            tune=tune,
            preset=preset,
            audiocodec=audiocodec,
            audiobitrate=audiobitrate,
            jpnaudiomap=japaneseaudio,
            engaudiomap=englishaudio,
            audiometa=audiometa,
            substream=subtitlestream,
            subtitle=subtitle,
            defaultsub=defaultsub,
        )
    },
)

if execute:
    ff.run()
else:
    print(ff.cmd)

# check output file for valid duration
valid_duration(outputfile, "OUTPUT")

if os.path.isfile("error.csv"):
    print(
        "Some media might have errors. Please check the error.csv file in this directory"
    )