import { createContext } from "solid-js";
import { createStore as createStore_ } from "solid-js/store";
import {
  addressSchema,
  createAddress,
  PostalAddressData,
  postalAddressSchema,
} from "./components/Address";
import { createLocalStore as createLocalStore_ } from "./localStore";
import { getUnixTime } from "date-fns";
import z, { Infer } from "myzod";

export const POSITION_TYPE_QUANTITY = "QUANTITY";
export const POSITION_TYPE_AGILE = "AGILE";

export const positionSchema = z.object({
  id: z.number(),
  name: z.string(),
  enabled: z.boolean(),
  type: z.literals(POSITION_TYPE_QUANTITY, POSITION_TYPE_AGILE),
  agilePointsMin: z.number().optional(),
  agilePointsMax: z.number().optional(),
  agileRiskFactor: z.number().optional(),
  number: z.string().optional(),
  description: z.string().optional(),
  quantity: z.number(),
  fixedDiscountPrice: z.number().optional(),
  itemPrice: z.number().optional(),
});

export type Position = Infer<typeof positionSchema>;

export const PRINT_TYPE_LETTER = "LETTER";
export const PRINT_TYPE_OFFER = "OFFER";
export const PRINT_TYPE_CONFIRMATION = "CONFIRMATION";
export const PRINT_TYPE_INVOICE = "INVOICE";

export type PrintType =
  | typeof PRINT_TYPE_LETTER
  | typeof PRINT_TYPE_OFFER
  | typeof PRINT_TYPE_CONFIRMATION
  | typeof PRINT_TYPE_INVOICE;

export const printTypeTitles = {
  [PRINT_TYPE_LETTER]: "Brief",
  [PRINT_TYPE_OFFER]: "Offerte",
  [PRINT_TYPE_CONFIRMATION]: "Auftragsbestätigung",
  [PRINT_TYPE_INVOICE]: "Rechnung",
};

export const printTypeSelectTitles = {
  ...printTypeTitles,
  [PRINT_TYPE_CONFIRMATION]: "Bestätigung",
};

export const createUiStore = () =>
  createStore_({
    lastSaved: 0,
    printType: PRINT_TYPE_INVOICE as PrintType,
    selectedPosition: undefined as undefined | number,
  });
export type UiStore = ReturnType<typeof createUiStore>;
export const UiStoreContext = createContext<UiStore>();

export const ADDRESS_LAYOUT_LEFT = "LEFT";
export const ADDRESS_LAYOUT_RIGHT = "RIGHT";
export type AddressLayout =
  | typeof ADDRESS_LAYOUT_LEFT
  | typeof ADDRESS_LAYOUT_RIGHT;

export const storeSchema = z.object({
  version: z.number(),
  project: z.object({
    orderNumber: z.string(),
    projectNumber: z.string(),
    deliveryNumber: z.string(),
    deliveryDate: z.number().optional(),
    date: z.number(),
    title: z.string().optional(),
    preface: z.string().optional(),
    conclusion: z.string().optional(),
  }),
  invoice: z.object({
    reference: z.string(),
    message: z.string(),
  }),
  fullWidthInvoice: z.boolean(),
  useCustomerAlternativeAddress: z.boolean(),
  customer: z.object({
    customerNumber: z.string(),
    vatNumber: z.string(),
    alternativeAddress: postalAddressSchema,
    debtorAddress: addressSchema,
  }),
  defaultItemPrice: z.number(),
  agileRiskFactor: z.number(),
  agileHoursPerStoryPoint: z.number(),
  defaultPositionType: z.literals(POSITION_TYPE_QUANTITY, POSITION_TYPE_AGILE),
  positions: z.array(positionSchema),
});
export type StoreObject = Infer<typeof storeSchema>;

export const CURRENT_VERSION = 1.5;

export const migrateState = (state: Record<string, any>) => {
  state.version = CURRENT_VERSION;
};

export const createStore = () =>
  createStore_<StoreObject>({
    version: CURRENT_VERSION,
    project: {
      orderNumber: "",
      projectNumber: "",
      deliveryNumber: "",
      date: getUnixTime(new Date()),
    },
    invoice: {
      reference: "",
      message: "",
    },
    fullWidthInvoice: true,
    useCustomerAlternativeAddress: false,
    customer: {
      customerNumber: "",
      vatNumber: "",
      alternativeAddress: createAddress<PostalAddressData>({
        name2: undefined,
      }),
      debtorAddress: createAddress(),
    },
    defaultPositionType: POSITION_TYPE_QUANTITY,
    defaultItemPrice: 0,
    agileRiskFactor: 0.7,
    agileHoursPerStoryPoint: 4,
    positions: [] as Position[],
  });

export type Store = ReturnType<typeof createStore>;
export const StoreContext = createContext<Store>();

export const localStoreSchema = z.object({
  // TODO: Move this to a cookie (advantage: ssr)
  showWelcome: z.boolean(),
  version: z.number(),
  vatNumber: z.string(),
  vatRate: z.number(),
  paymentTerms: z.string().optional(),
  iban: z.string(),
  creditor: addressSchema,
  addressLayout: z.literals(ADDRESS_LAYOUT_LEFT, ADDRESS_LAYOUT_RIGHT),
  font: z.string(),
  customAddress: postalAddressSchema,
  contact: z.object({
    name: z.string(),
    phone: z.string(),
    email: z.string(),
  }),
  showLufraiWatermark: z.boolean(),
  // TODO: Signature Image
  logo: z
    .object({
      type: z.string(),
      url: z.string(),
      width: z.number(),
      height: z.number(),
    })
    .optional(),
  useCustomAddress: z.boolean(),
});
export type LocalStoreObject = Infer<typeof localStoreSchema>;

export const migrateLocalState = (state: Record<string, any>) => {
  if (state.version === 1) {
    state.addressLayout = ADDRESS_LAYOUT_LEFT;

    state.version = 1.3;
  }

  if (state.version === 1.3) {
    state.font = "default";

    state.version = 1.5;
  }

  state.version = CURRENT_VERSION;
};

export const migrateInfoLog = (oldVersion: number, newVersion: number) =>
  console.info(
    `Migrated document schema from version ${oldVersion} to ${newVersion}`
  );

export const createLocalStore = () =>
  createLocalStore_<LocalStoreObject>(
    {
      version: CURRENT_VERSION,
      showWelcome: true,
      vatNumber: "",
      vatRate: 0.0,
      paymentTerms: undefined,
      creditor: createAddress(),
      font: "default",
      addressLayout: ADDRESS_LAYOUT_RIGHT,
      customAddress: createAddress<PostalAddressData>({ name2: undefined }),
      contact: {
        name: "",
        phone: "",
        email: "",
      },
      logo: undefined,
      showLufraiWatermark: true,
      useCustomAddress: false,
      iban: "",
    },
    {
      prefix: "invoice-app",
      migrate: (getState) => {
        const version = JSON.parse(
          localStorage.getItem("invoice-app-version") || "-1"
        );

        if (version == -1) return false;

        if (version !== CURRENT_VERSION) {
          migrateLocalState(getState());
          migrateInfoLog(version, CURRENT_VERSION);
          return true;
        }

        return false;
      },
    }
  );

export type LocalStore = ReturnType<typeof createLocalStore>;
export const LocalStoreContext = createContext<LocalStore>();
