/* eslint-disable compat/compat */
import {
  model,
  Model,
  modelAction,
  ModelAutoTypeCheckingMode,
  setGlobalConfig,
  tProp,
  types,
} from 'mobx-keystone';
import { v4 as uuidv4 } from 'uuid';
import TarifRow from './TarifRow';

setGlobalConfig({
  modelAutoTypeChecking: ModelAutoTypeCheckingMode.AlwaysOn,
});

@model('keystone/Application/Tarif')
export default class Tarif extends Model({
  id: tProp(types.string, () => uuidv4()),
  name: tProp(types.string),
  type: tProp(types.number),
  startDate: tProp(types.number), // epoch ms
  endDate: tProp(types.number), // epoch ms
  startPrice: tProp(types.number),
  maxPrice: tProp(types.number),
  exitTimeConf: tProp(types.number),
  exitTime: tProp(types.number), // epoch ms (duration-like in your UI)
  tarifRows: tProp(types.array(types.model<TarifRow>(TarifRow)), () => []),
}) {
  @modelAction
  setName(name: string) {
    this.name = name;
  }

  get allKeystone() {
    return this;
  }

  get all() {
    const all = [];
    for (let i = 0; i < this.tarifRows.length; i += 1) {
      all.push(this.tarifRows[i]);
    }
    return all;
  }

  get allClean() {
    const all: any[] = [];
    for (let i = 0; i < this.tarifRows.length; i += 1) {
      all.push(this.tarifRows[i].allClean);
    }
    all.sort((a, b) => (a.sequence > b.sequence ? 1 : -1));
    return all;
  }

  /**
   * Expands repeat > 1 rows into repeated entries.
   * NOTE: this mutates "done" on the same object reference as before
   * (kept as-is from your original code).
   */
  get allCleanFix() {
    const all: any[] = [];
    const allWithRepeat: any[] = [];
    for (let i = 0; i < this.tarifRows.length; i += 1) {
      all.push(this.tarifRows[i].allClean);
    }
    all.sort((a, b) => (a.sequence > b.sequence ? 1 : -1));

    for (let z = 0; z < all.length; z += 1) {
      if (all[z].repeat <= 1) {
        allWithRepeat.push(all[z]);
      }
      if (all[z].repeat > 1) {
        for (let x = 0; x < all[z].repeat; x += 1) {
          all[z].done = false;
          allWithRepeat.push(all[z]);
        }
      }
    }
    return allWithRepeat;
  }

  /**
   * Helper: interpret timeSlot as a UTC duration (ms since epoch with UTCHours/UTCMinutes).
   */
  private durationMsToMinutes(ms: number) {
    const d = new Date(ms || 0);
    return d.getUTCHours() * 60 + d.getUTCMinutes();
  }

  /**
   * Helper: set a Date to a "clock time" using UTC, avoiding local TZ/DST drift.
   */
  private setClockUtc(d: Date, minutesFromMidnight: number) {
    d.setUTCHours(0, 0, 0, 0);
    d.setUTCMinutes(minutesFromMidnight);
  }

  get allPerDay() {
    const all = this.allCleanFix;
    const startDate = new Date();

    // Build a week-like timeline (your original loop uses 10080 mins)
    // We keep your "dayFix" formatting logic but make it UTC-safe.
    const allPerHour: any[] = [];
    let totalMinutes = 0;
    let totalPrice = 0;
    let lastSeq = 0;

    for (let i = 0; i <= 10080; i += 1) {
      if (i > totalMinutes && lastSeq < all.length) {
        totalMinutes += this.durationMsToMinutes(all[lastSeq].timeSlot);
        all[lastSeq].done = true;
        totalPrice += parseFloat(all[lastSeq].amount);
        if (all[lastSeq].repeat !== 0) {
          lastSeq += 1;
        }
      }

      if (i % 60 === 0) {
        this.setClockUtc(startDate, i);

        // original code uses "date" to show days; keep it but use UTC
        startDate.setUTCDate(1); // reset day to 1 (UTC)
        this.setClockUtc(startDate, i);

        const dayFix = startDate.getUTCDate() - 1;

        let formatedTime = `${dayFix.toString().padStart(2, '0')}:${startDate
          .getUTCHours()
          .toString()
          .padStart(2, '0')}:${startDate
          .getUTCMinutes()
          .toString()
          .padStart(2, '0')}`;

        if (i % 1440 === 0 && i !== 0) {
          formatedTime = `${(dayFix - 1).toString().padStart(2, '0')}:24:00`;
        }

        allPerHour.push({
          time: formatedTime,
          price: totalPrice,
        });
      }
    }

    return allPerHour;
  }

  get allPerHalfHour() {
    const all = this.allCleanFix;
    const startDate = new Date();
    const allPerHour: any[] = [];
    let totalMinutes = 0;
    let totalPrice = 0;
    let lastSeq = 0;

    for (let i = 0; i <= 1440; i += 1) {
      if (i > totalMinutes && lastSeq < all.length) {
        totalMinutes += this.durationMsToMinutes(all[lastSeq].timeSlot);
        all[lastSeq].done = true;
        totalPrice += parseFloat(all[lastSeq].amount);
        if (all[lastSeq].repeat !== 0) {
          lastSeq += 1;
        }
      }

      if (i % 30 === 0) {
        this.setClockUtc(startDate, i);

        let formatedTime = `${startDate
          .getUTCHours()
          .toString()
          .padStart(2, '0')}:${startDate
          .getUTCMinutes()
          .toString()
          .padStart(2, '0')}`;

        if (i === 1440) formatedTime = '24:00';

        allPerHour.push({
          time: formatedTime,
          price: totalPrice,
        });
      }
    }

    return allPerHour;
  }

  get allPerMinute() {
    const all = this.allCleanFix;
    const startDate = new Date();
    const allPerMinute: any[] = [];
    let totalMinutes = 0;
    let totalPrice = 0;
    let lastSeq = 0;

    for (let i = 0; i <= 1440; i += 1) {
      if (i > totalMinutes && lastSeq < all.length) {
        totalMinutes += this.durationMsToMinutes(all[lastSeq].timeSlot);
        all[lastSeq].done = true;
        totalPrice += parseFloat(all[lastSeq].amount);
        if (all[lastSeq].repeat !== 0) {
          lastSeq += 1;
        }
      }

      this.setClockUtc(startDate, i);

      let formatedTime = `${startDate
        .getUTCHours()
        .toString()
        .padStart(2, '0')}:${startDate
        .getUTCMinutes()
        .toString()
        .padStart(2, '0')}`;

      if (i === 1440) formatedTime = '24:00';

      allPerMinute.push({
        time: formatedTime,
        price: totalPrice,
      });
    }

    return allPerMinute;
  }

  get allPerSecond() {
    const all = this.allCleanFix;
    const startDate = new Date();
    const allPerSecond: any[] = [];
    let totalSeconds = 0;
    let totalPrice = 0;
    let lastSeq = 0;

    // Your original loop goes to 7200 seconds (2 hours). Keep it.
    for (let i = 0; i <= 7200; i += 1) {
      // run trough the sequences
      for (let z = 0; z < all.length; z += 1) {
        if (i > totalSeconds && lastSeq < all.length) {
          const d = new Date(all[lastSeq].timeSlot || 0);
          totalSeconds += d.getUTCHours() * 3600;
          totalSeconds += d.getUTCMinutes() * 60;

          all[lastSeq].done = true;
          totalPrice += parseFloat(all[lastSeq].amount);
          if (all[lastSeq].repeat !== 0) {
            lastSeq += 1;
          }
        }
      }

      startDate.setUTCHours(0, 0, 0, 0);
      startDate.setUTCSeconds(i);

      let formatedTime = `${startDate
        .getUTCHours()
        .toString()
        .padStart(2, '0')}:${startDate
        .getUTCMinutes()
        .toString()
        .padStart(2, '0')}:${startDate
        .getUTCSeconds()
        .toString()
        .padStart(2, '0')}`;

      if (i === 7200) {
        formatedTime = '2:00:00';
      }

      allPerSecond.push({
        time: formatedTime,
        price: totalPrice,
      });
    }

    return allPerSecond;
  }

  priceToPay(seconds: number) {
    const all = this.allCleanFix;
    let totalSeconds = 0;
    let totalPrice = 0;
    let lastSeq = 0;

    const promise = new Promise((resolve, reject) => {
      for (let i = 0; i <= seconds; i += 1) {
        for (let z = 0; z < all.length; z += 1) {
          if (i > totalSeconds && lastSeq < all.length) {
            const d = new Date(all[lastSeq].timeSlot || 0);
            totalSeconds += d.getUTCHours() * 3600;
            totalSeconds += d.getUTCMinutes() * 60;

            all[lastSeq].done = true;
            totalPrice += parseFloat(all[lastSeq].amount);
            if (all[lastSeq].repeat !== 0) {
              lastSeq += 1;
            }
          }
        }
      }

      resolve(totalPrice);
      // eslint-disable-next-line prefer-promise-reject-errors
      setTimeout(() => reject(-1), 3000);
    });

    return promise;
  }

  @modelAction
  addTarifRow(tarifRow: TarifRow) {
    tarifRow.sequence = this.tarifRows.length + 1;
    this.tarifRows.push(tarifRow);
  }

  get highestSequence() {
    let highestSequence = 1;
    for (let i = 0; i < this.tarifRows.length; i += 1) {
      if (highestSequence < this.tarifRows[i].sequence) {
        highestSequence = this.tarifRows[i].sequence;
      }
    }
    return highestSequence;
  }

  @modelAction
  checkSequenceWithoutElement(id: string, sequence: number) {
    let result = false;
    for (let i = 0; i < this.tarifRows.length; i += 1) {
      if (this.tarifRows[i].id !== id) {
        if (this.tarifRows[i].sequence === sequence) {
          result = true;
        }
      }
    }
    return result;
  }

  @modelAction
  checkSequence(sequence: number) {
    if (this.tarifRows.length - 1 <= sequence) {
      return false;
    }

    if (
      this.tarifRows.find((o: { sequence: number }) => o.sequence === sequence)
    ) {
      return true;
    }

    return false;
  }

  @modelAction
  change(
    name: string,
    type: number,
    startDate: number,
    endDate: number,
    startPrice: number,
    maxPrice: number,
    exitTimeConf: number,
    exitTime: number,
    tarifRows: TarifRow[]
  ) {
    this.name = name;
    this.type = type;
    this.startDate = +startDate;
    this.endDate = +endDate;
    this.startPrice = startPrice;
    this.maxPrice = maxPrice;
    this.exitTimeConf = exitTimeConf;
    this.exitTime = +exitTime;
    this.tarifRows = tarifRows;
  }

  @modelAction
  remove(tarifRow: any) {
    const index = this.tarifRows.indexOf(tarifRow);
    if (index >= 0) {
      this.tarifRows.splice(index, 1);
    }
  }

  @modelAction
  removeByIds(arrayOfIds: any) {
    if (typeof arrayOfIds !== undefined) {
      arrayOfIds.map((id: string) => {
        return this.remove(
          this.tarifRows.find((x: { id: string }) => x.id === id)
        );
      });
    }
  }
}
