use fiscalprinter::{Setup, PrinterResult, Report, Document, FiscalPrinter, FiscalPrinterDriver, ReportType, SetupType};
use serialport::SerialPort;
use fiscalprinter::Result;

use crate::pnp::driver::Driver;

#[derive(Clone, Copy)]
pub struct Printer {
    _driver: Driver
}

const ASCII_SEPARATOR_CHARACTER: u8 = 28;
//  Command Types
const ASCII_COMMAND_REPORT: u8 = 57;
const ASCII_X_REPORT: u8 = 88;
const ASCII_X_REPORT_ACTION_PRINT: u8 = 84;
//  Status
const ASCII_COMMAND_STATUS: u8 = 56;
//  Status Type
const ASCII_STATUS_TYPE_N: u8 = 78;
//  Z
const ASCII_Z_REPORT: u8 = 90;

impl FiscalPrinter for Printer {
    
    fn new() -> Self {
        Printer { 
            _driver: Driver::new()
        }
    }
    fn setup(&mut self, mut _handler: &mut Box<dyn SerialPort>, _setup: Setup) -> Result<PrinterResult> {
        println!("setup");
        if matches!(_setup.setup_type, SetupType::Status) {
            let mut _command = vec![];
            _command.push(ASCII_COMMAND_STATUS);
            _command.push(ASCII_SEPARATOR_CHARACTER);
            _command.push(ASCII_STATUS_TYPE_N);
            let ok = self._driver.send_command(_handler, _command).expect("Error building command");
            println!("Is {}", ok);
        }
        return Ok(PrinterResult { 
            id: _setup.setup_id, 
            last_invoice_no: None, 
            last_credit_memo_no: None, 
            last_debit_memo_no: None, 
            last_non_fiscal_no: None, 
            last_closing_no: None 
        });
    }

    fn print_report(&mut self, mut _handler: &mut Box<dyn SerialPort>, _report: Report) -> Result<PrinterResult> {
        println!("print_report {:?}", _report.report_type);
        if matches!(_report.report_type, ReportType::XReport) {
            let mut _command = vec![];
            _command.push(ASCII_COMMAND_REPORT);
            _command.push(ASCII_SEPARATOR_CHARACTER);
            _command.push(ASCII_X_REPORT);
            _command.push(ASCII_SEPARATOR_CHARACTER);
            _command.push(ASCII_X_REPORT_ACTION_PRINT);
            self._driver.send_command(_handler, _command).expect("Error building command");
        } else if matches!(_report.report_type, ReportType::ZReport) {
            let mut _command = vec![];
            _command.push(ASCII_COMMAND_REPORT);
            _command.push(ASCII_SEPARATOR_CHARACTER);
            _command.push(ASCII_Z_REPORT);
            _command.push(ASCII_SEPARATOR_CHARACTER);
            _command.push(ASCII_X_REPORT_ACTION_PRINT);
            self._driver.send_command(_handler, _command).expect("Error building command");
        }
        //  Default
        return Ok(PrinterResult { 
            id: _report.report_id, 
            last_invoice_no: None, 
            last_credit_memo_no: None, 
            last_debit_memo_no: None, 
            last_non_fiscal_no: None, 
            last_closing_no: None 
        });
    }

    fn print_document(&mut self, mut _handler: &mut Box<dyn SerialPort>, _document: Document) -> Result<PrinterResult> {
        println!("print_document");
        return Ok(PrinterResult { 
            id: _document.document_id,
            last_invoice_no: None, 
            last_credit_memo_no: None, 
            last_debit_memo_no: None, 
            last_non_fiscal_no: None, 
            last_closing_no: None 
        });
    }
}