import type {
  CreateTruckLaneScheduleRequest,
  TruckLaneMoveTargetRequest,
  TruckLaneScheduleLineRequest,
} from "@/app/api/shop/actions";
import { movesToScheduleLines } from "@/components/Shop/scheduleLineAdapter";
import { normalizeStoreId } from "@/app/utils/formatUtil";
import type {
  ScheduleLaneOption,
  ScheduleMoveSelection,
} from "@/components/Shop/ScheduleChangeModal";
import type {
  ScheduleModification,
  ScheduleDragWorkspaceState,
  ScheduledDeleteSnapshot,
} from "@/components/Shop/scheduleDragWorkspace";

export function buildScheduleMoveFromSelection(
  truckRowId: number,
  selection: ScheduleMoveSelection,
  lane: ScheduleLaneOption,
  toDistrictReference?: string | null,
): TruckLaneMoveTargetRequest {
  return {
    truckRowId,
    toTruckLanceCode: lane.truckLanceCode,
    toRemark:
      lane.remark != null && String(lane.remark).trim() !== ""
        ? String(lane.remark).trim()
        : null,
    toStoreId: normalizeStoreId(lane.storeId),
    toLoadingSequence: selection.toLoadingSequence,
    toDistrictReference: toDistrictReference ?? null,
  };
}

export function buildDeleteScheduleLine(
  truckRowId: number,
  lane: ScheduleLaneOption,
  shopCode: string,
  shopName: string,
): TruckLaneScheduleLineRequest {
  return {
    action: "DELETE",
    truckRowId,
    toTruckLanceCode: lane.truckLanceCode,
    toRemark:
      lane.remark != null && String(lane.remark).trim() !== ""
        ? String(lane.remark).trim()
        : null,
    toStoreId: normalizeStoreId(lane.storeId),
    shopCode,
    shopName,
  };
}

function districtByTruckRowIdFromPlanned(
  plannedLanes?: ScheduleDragWorkspaceState,
): Map<number, string | null> {
  const map = new Map<number, string | null>();
  if (!plannedLanes) return map;
  for (const lane of plannedLanes) {
    for (const shop of lane.shops) {
      map.set(shop.truckRowId, shop.districtReferenceRaw);
    }
  }
  return map;
}

export function buildScheduleMovesFromMappings(
  mappings: Record<number, ScheduleMoveSelection>,
  lanes: ScheduleLaneOption[],
  plannedLanes?: ScheduleDragWorkspaceState,
): TruckLaneMoveTargetRequest[] {
  const laneById = new Map(lanes.map((l) => [l.id, l]));
  const districtByTruckRowId = districtByTruckRowIdFromPlanned(plannedLanes);
  const out: TruckLaneMoveTargetRequest[] = [];
  for (const [id, sel] of Object.entries(mappings)) {
    const truckRowId = Number(id);
    const lane = laneById.get(sel.laneId);
    if (!lane || !Number.isFinite(truckRowId)) continue;
    const seq = sel.toLoadingSequence;
    if (!Number.isFinite(seq) || seq < 0) continue;
    out.push(
      buildScheduleMoveFromSelection(
        truckRowId,
        sel,
        lane,
        districtByTruckRowId.get(truckRowId),
      ),
    );
  }
  return out;
}

export function buildScheduleLinesFromPlan(input: {
  modifications: ScheduleModification[];
  pendingDeletes: ScheduledDeleteSnapshot[];
  lanes: ScheduleLaneOption[];
  plannedLanes?: ScheduleDragWorkspaceState;
}): TruckLaneScheduleLineRequest[] {
  const laneById = new Map(input.lanes.map((l) => [l.id, l]));
  const deleteIds = new Set(input.pendingDeletes.map((d) => d.truckRowId));
  const mappings = Object.fromEntries(
    input.modifications
      .filter((m) => !deleteIds.has(m.truckRowId))
      .map((m) => [
        m.truckRowId,
        { laneId: m.toLaneId, toLoadingSequence: m.newLoadingSequence },
      ]),
  );
  const moveLines = movesToScheduleLines(
    buildScheduleMovesFromMappings(
      mappings,
      input.lanes,
      input.plannedLanes,
    ),
  );
  const deleteLines = input.pendingDeletes
    .map((d) => {
      const lane = laneById.get(d.fromLaneId);
      if (!lane) return null;
      return buildDeleteScheduleLine(
        d.truckRowId,
        lane,
        d.shopCode,
        d.displayName,
      );
    })
    .filter((line): line is TruckLaneScheduleLineRequest => line != null);
  return [...moveLines, ...deleteLines];
}

export function buildScheduleMovesFromModifications(
  modifications: ScheduleModification[],
  lanes: ScheduleLaneOption[],
  plannedLanes?: ScheduleDragWorkspaceState,
  pendingDeletes: ScheduledDeleteSnapshot[] = [],
): TruckLaneMoveTargetRequest[] {
  const deleteIds = new Set(pendingDeletes.map((d) => d.truckRowId));
  const mappings = Object.fromEntries(
    modifications
      .filter((m) => !deleteIds.has(m.truckRowId))
      .map((m) => [
        m.truckRowId,
        { laneId: m.toLaneId, toLoadingSequence: m.newLoadingSequence },
      ]),
  );
  return buildScheduleMovesFromMappings(mappings, lanes, plannedLanes);
}

export function buildCreateScheduleRequest(input: {
  executeAt: string;
  note?: string | null;
  mappings: Record<number, ScheduleMoveSelection>;
  lanes: ScheduleLaneOption[];
  plannedLanes?: ScheduleDragWorkspaceState;
  pendingDeletes?: ScheduledDeleteSnapshot[];
  modifications?: ScheduleModification[];
}): CreateTruckLaneScheduleRequest {
  if (input.modifications != null) {
    return {
      executeAt: input.executeAt,
      note: input.note ?? null,
      lines: buildScheduleLinesFromPlan({
        modifications: input.modifications,
        pendingDeletes: input.pendingDeletes ?? [],
        lanes: input.lanes,
        plannedLanes: input.plannedLanes,
      }),
    };
  }
  const moves = buildScheduleMovesFromMappings(
    input.mappings,
    input.lanes,
    input.plannedLanes,
  );
  const deleteLines = (input.pendingDeletes ?? [])
    .map((d) => {
      const lane = input.lanes.find((l) => l.id === d.fromLaneId);
      if (!lane) return null;
      return buildDeleteScheduleLine(
        d.truckRowId,
        lane,
        d.shopCode,
        d.displayName,
      );
    })
    .filter((line): line is TruckLaneScheduleLineRequest => line != null);
  return {
    executeAt: input.executeAt,
    note: input.note ?? null,
    lines: [...movesToScheduleLines(moves), ...deleteLines],
  };
}

export function buildCreateScheduleRequestFromModifications(input: {
  executeAt: string;
  note?: string | null;
  modifications: ScheduleModification[];
  lanes: ScheduleLaneOption[];
  plannedLanes?: ScheduleDragWorkspaceState;
  pendingDeletes?: ScheduledDeleteSnapshot[];
}): CreateTruckLaneScheduleRequest {
  return {
    executeAt: input.executeAt,
    note: input.note ?? null,
    lines: buildScheduleLinesFromPlan({
      modifications: input.modifications,
      pendingDeletes: input.pendingDeletes ?? [],
      lanes: input.lanes,
      plannedLanes: input.plannedLanes,
    }),
  };
}
