#!/usr/bin/python
# -*- coding: utf-8 -*-
from openpyxl import load_workbook
from pathlib import Path
from my_folders import source_file_folder
from dataclasses import dataclass, asdict
import matplotlib.pyplot as plt
from itertools import islice


def batched(iterable, batch_size):
    it = iter(iterable)
    while _batch := list(islice(it, batch_size)):
        yield _batch


@dataclass(frozen=True)
class Measure:
    ts: float       # time stamp
    v: float
    i: float


@dataclass
class RawMeasure:
    ts: int
    ch: int
    v: float


@dataclass(frozen=True)
class DischargePoint(Measure):
    c: float        # Capacity


column_indexes = {      # columns indexes that we want to import: None means try to find the column
    'TimeStamp': 0,
    'Ibatt': None,
    'Vbatt': None,
}


def available_measurements(s_in: str):
    """
    generates the series of RawMeasure contained in the s_in string

    :param s_in:
    :return:
    """
    fields = s_in.strip().strip('\n').replace('VDC1', 'VDC 1').split()
    for ts, ch, chn, value, unit in batched(fields, 5):
        if ch != 'Ch' or not unit.endswith('DC'):
            continue
        yield RawMeasure(ts=int(ts), ch=int(chn), v=float(value))


def load_a_txt_file(path: Path, duts: dict[str, tuple[int, int]]) -> dict[str, list[Measure]]:
    """Returns a sorted list of Measures()"""

    # 1742542808 Ch 101 4.6694100e-03 VDC 1742542808 Ch 102 3.6288222e+00 VDC
    # 1742542838 Ch 101 4.6651780e-03 VDC 1742542838 Ch 102 3.6315371e+00 VDC
    # 1743758985 Ch 101 2.2117630e-03 VDC 1743758985 Ch 102 2.9622319e+00 VDC1743758985 Ch 103 1.9700000e-03 VDC 1743758985 Ch 104 3.0066588e+00 VDC
    # 1743759015 Ch 101 2.1362400e-03 VDC 1743759015 Ch 102 3.0225466e+00 VDC1743759015 Ch 103 1.9600170e-03 VDC 1743759015 Ch 104 3.0766279e+00 VDC
    # 1743759046 Ch 101 2.1291870e-03 VDC 1743759046 Ch 102 3.0660180e+00 VDC1743759046 Ch 103 1.9516620e-03 VDC 1743759046 Ch 104 3.1234983e+00 VDC
    # 1743759076 Ch 101 2.1232190e-03 VDC 1743759076 Ch 102 3.1013554e+00 VDC1743759076 Ch 103 1.9452600e-03 VDC 1743759076 Ch 104 3.1604323e+00 VDC
    # 1743759106 Ch 101 2.1214820e-03 VDC 1743759106 Ch 102 3.1316431e+00 VDC1743759106 Ch 103 1.9383150e-03 VDC 1743759106 Ch 104 3.1913389e+00 VDC
    #      0      1  2    3            4      5       6  7     8            9
    discharges = {k: [] for k in duts.keys()}
    with open(path, 'r') as fin:
        for raw_line in fin:
            if len(raw_line) < 10:      # arbitrario per rimuovere linee sicuramente sbagliate
                continue
            if 'slv' in raw_line.lower():
                continue
            fields = raw_line.strip().strip('\n').split()
            if len(fields) < 10:
                continue                # remove malformed lines
            measures = {m.ch: m for m in available_measurements(raw_line)}
            for dut, dsch_ptis in discharges.items():
                chi, chv = duts[dut]
                i = measures[chi]
                v = measures[chv]
                dsch_ptis.append(Measure(ts=i.ts, i=i.v / 0.010007, v=v.v))

    for disc in discharges.values():
        disc.sort(key=lambda x: x.ts)
    return discharges


def compute_discharge(measures: list[Measure], initial_capacity: float = 0.0) -> list[DischargePoint]:
    discharge_sequence = []
    last_m = None
    t0 = None
    for m in measures:
        if t0 is None:
            t0 = m.ts
        if last_m is not None:
            initial_capacity += (m.i + last_m.i) * 0.5 * (m.ts - last_m.ts) / 3600.0
        meas = asdict(m)
        meas['ts'] -= t0
        discharge_sequence.append(DischargePoint(c=initial_capacity, **meas))
        last_m = m
    return discharge_sequence


def show_a_discharge(discharge: list[DischargePoint], title='Title'):
    out_name = f'{title}.png'
    if '100_per' in title:
        title = 'Battery Option: 100%'
    elif '80_per' in title:
        title = 'Battery Option: 80%'
    else:
        title = f'Battery Option: OFF  ({title})'
    how_many = 1
    fig, axs_maybe = plt.subplots(how_many, 1, tight_layout=False, figsize=(7.85, 5.38))
    # fig.suptitle(f'Recahrging Behavior', fontsize=20)
    # fig, ax = plt.subplots(figsize=(11, 6))
    if how_many == 1:
        axs = (axs_maybe,)
    else:
        axs = axs_maybe
    ax = axs[0]
    ax.grid(True)
    axr = ax.twinx()
    # ax.set_xlim(0.0, 125)
    mins = []
    vbatt = []
    ibatt = []
    caps = []
    for dp in discharge:
        mins.append(dp.ts/60.0)
        vbatt.append(dp.v)
        ibatt.append(dp.i * 1000.0)
        caps.append(dp.c * 1000.0)
    ax.plot(mins, vbatt, color='g', lw=3, alpha=0.5, label='Battery Voltage')
    axr.plot(mins, caps, color='b', lw=3, alpha=0.5, label='Accumulated Capacity')
    axr.plot(mins, ibatt, color='r', lw=3, alpha=0.5, label='Charging Current')
    ax.set_xlim(0, None)
    ax.set_ylim(3.0, 4.3)
    axr.set_ylim(0, None)
    axr.set_ylabel('Capacity [mAh] / Current [mA]')
    ax.set_xlabel('time [minutes]')
    ax.set_ylabel('Cell Voltage [V]')
    ax.set_title(title)
    axr.legend(loc='center right')
    ax.legend(loc='upper left')
    txt = f'Total Capacity: {caps[-1]:.1f} mAh'
    print(txt)
    axr.text(mins[-1], caps[-1] - 150, txt, ha='right', fontsize=10, bbox={'facecolor': 'cyan', 'alpha': 0.7, 'pad': 5})
    # fig.tight_layout()
    fig.savefig(out_name, dpi=300)
    plt.close()


DUTS = {
    'SLV15': (101, 102),
    'SLV19': (103, 104),
}

if __name__ == '__main__':
    for f in source_file_folder.iterdir():
        if f.stem != 'log_2025_04_04_09':
            continue
        if f.is_file():
            if f.suffix.lower() == '.xlsx':
                print('skipping ', f)
            elif f.suffix.lower() == '.txt':
                print(f)
                measured_data = load_a_txt_file(f, DUTS)
                # print(measured_data)
            else:
                continue
            for name, discharge_points in measured_data.items():
                discharge = compute_discharge(discharge_points)
                stem_under = f.stem.replace(' ', '_')
                show_a_discharge(discharge, title=f'{name}_{stem_under}')
