#!/usr/bin/php
<?php

require_once('/usr/share/ombutel/www/includes/cli.php');

use ombutel\db;
use ombutel\timezone;

// init options object
$options = (object) [
	'dry_run' => false,
	'verbose' => false,
	'from_date' => null,
	'to_date' => null
];

// Rename recording filename
function rename_file($filename, $new_filename) {
	if (!rename($filename, $new_filename)) {
		throw new Exception("Unable to move file {$filename} to {$new_filename}");
	}
}

// Remove odd characters
function filter($value) {
	return preg_replace('_[\\{}<>~$;&|*?#`"\'/]+_', '', $value);
}

function validate_date($date, $format = 'Y-m-d') {
	$datetime = DateTime::createFromFormat($format, $date, new DateTimeZone('utc'));
	return ($datetime && $datetime->format($format) == $date);
}

function parse_args() {
	global $argc, $options;
	$args = getopt("dvf:t:", [ 'dry-run', 'verbose', 'from_date:', 'to_date:' ]);
	if($argc < 2) { return; }
	foreach($args as $arg => $value) {
		switch($arg) {
			//do nothing. Just output what script will do
			case 'd':
			case 'dry-run': {
				$options->dry_run = true;
				break;
			}
			//verbose
			case 'v':
			case 'verbose': {
				$options->verbose = true;
				break;
			}
			//start date
			case 'f':
			case 'from_date': { //format YYYY-MM-DD
				if(validate_date($value)) {
					$options->from_date = $value;
				}
				break;
			}
			//end date
			case 't':
			case 'to_date': { //format YYYY-MM-DD
				if(validate_date($value)) {
					$options->to_date = $value;
					break;
				}
			}
		}
	}
}

function where(&$offset = 0, $batch_size) {
	global $options;
	$cond[] = "recfile is not null";
	$cond[] = "recfile != ''";
	if($options->from_date != null && $options->to_date != null) { // assuming from/to dates validity is impeccable
		$cond[] = "calldate between '{$options->from_date} 00:00:00' and '{$options->to_date} 00:00:00'";
	} elseif($options->from_date != null) {
		$cond[] = "calldate > '{$options->from_date} 00:00:00'";
	} elseif($options->to_date != null) {
		$cond[] = "calldate < '{$options->to_date} 00:00:00'";
	}
	$cond[] = "cdr_id > {$offset} order by cdr_id limit {$batch_size}";
	return implode(" and ", $cond);
}

function run() {
	global $options;
	$offset = 0;
	$batch_size = 100;
	$done = false;
	$system_timezone = new DateTimeZone(timezone::server()->identifier);
	while(!$done) {
		db::begin_transaction();
		$where = where($offset, $batch_size);
		$recordings = iterator_to_array(db::query(
			"select
				`cdr_id`,
				unix_timestamp(`calldate`) as `calldate`,
				`calltype`,
				`duration`,
				`uniqueid`,
				`src`,
				`dst`,
				`recfile`
			from `asterisk`.`cdr`
			where " . $where
		));
		if($recordings) {
			foreach($recordings as $record) {
				$offset = $record->cdr_id;
				if(file_exists($record->recfile)) {
					$path_parts = pathinfo($record->recfile);
					if(preg_match('/^(INCOMING|OUTGOING)/', $path_parts['basename'])) {
						continue; //skip already modifed recording filenames
					}

					$filename_parts = [];
					$filename_parts[] = ($record->calltype == 3) ? 'OUTGOING' : 'INCOMING';
					$filename_parts[] = ($src = filter($record->src)) ? $src : "unknown";
					$filename_parts[] = ($dst = filter($record->dst)) ? $dst : "unknown";
					$calldate = (new DateTime('now', $system_timezone))
						->setTimestamp($record->calldate)
						->format('Y-m-d\TH-i-s');
					$filename_parts[] = $calldate;
					$filename_parts[] = $record->duration;
					$filename_parts[] = $record->uniqueid;

					$new_filename = implode("_", $filename_parts) .".{$path_parts['extension']}";
					$new_filename_path = implode("/", [ $path_parts['dirname'], $new_filename ]);

					// Check for corresponding transcription file
					$transcription_file = str_replace('.wav', '.json', $record->recfile);
					$new_transcription_filename = implode("_", $filename_parts) .".json";
					$new_transcription_path = implode("/", [ $path_parts['dirname'], $new_transcription_filename ]);

					if($options->dry_run || $options->verbose) {
						var_dump("renaming {$record->recfile} to {$new_filename_path}");
						if(file_exists($transcription_file)) {
							var_dump("renaming {$transcription_file} to {$new_transcription_path}");
						}
					} elseif(!$options->dry_run) {
						// Rename recording file
						rename_file($record->recfile, $new_filename_path);
						db::query("update
							`asterisk`.`cdr`
							set `recfile` = ?
							where `recfile` = ?",
							$new_filename_path,
							$record->recfile
						);

						// Rename transcription file if it exists
						if(file_exists($transcription_file)) {
							rename_file($transcription_file, $new_transcription_path);
							db::query("update
								`asterisk`.`tcdr`
								set `transfile` = ?
								where `transfile` = ?",
								$new_transcription_path,
								$transcription_file
							);
						}
					}
				}
			}
			db::commit();
		} else {
			db::commit();
			$done = true;
		}
	}
}

try {
	parse_args();
	run();
} catch (Exception $e) {
	error_log($e->getMessage());
}

?>
