import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';

describe('Entity Relationship Diagram', () => {
  it('should render a simple ER diagram', () => {
    imgSnapshotTest(
      `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      { logLevel: 1 }
    );
  });

  it('should render an ER diagram with a recursive relationship', () => {
    imgSnapshotTest(
      `
    erDiagram
        CUSTOMER ||..o{ CUSTOMER : refers
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      { logLevel: 1 }
    );
  });

  it('should render an ER diagram with multiple relationships between the same two entities', () => {
    imgSnapshotTest(
      `
    erDiagram
        CUSTOMER ||--|{ ADDRESS : "invoiced at"
        CUSTOMER ||--|{ ADDRESS : "receives goods at"
      `,
      { logLevel: 1 }
    );
  });

  it('should render a cyclical ER diagram', () => {
    imgSnapshotTest(
      `
    erDiagram
        A ||--|{ B : likes
        B ||--|{ C : likes
        C ||--|{ A : likes
      `,
      { logLevel: 1 }
    );
  });

  it('should render a not-so-simple ER diagram', () => {
    imgSnapshotTest(
      `
    erDiagram
        CUSTOMER }|..|{ DELIVERY-ADDRESS : has
        CUSTOMER ||--o{ ORDER : places
        CUSTOMER ||--o{ INVOICE : "liable for"
        DELIVERY-ADDRESS ||--o{ ORDER : receives
        INVOICE ||--|{ ORDER : covers
        ORDER ||--|{ ORDER-ITEM : includes
        PRODUCT-CATEGORY ||--|{ PRODUCT : contains
        PRODUCT ||--o{ ORDER-ITEM : "ordered in"
      `,
      { logLevel: 1 }
    );
  });

  it('should render multiple ER diagrams', () => {
    imgSnapshotTest(
      [
        `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
        `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      ],
      { logLevel: 1 }
    );
  });

  it('should render an ER diagram with blank or empty labels', () => {
    imgSnapshotTest(
      `
    erDiagram
        BOOK }|..|{ AUTHOR : ""
        BOOK }|..|{ GENRE : " "
        AUTHOR }|..|{ GENRE : "  "
      `,
      { logLevel: 1 }
    );
  });

  it('should render an ER diagrams when useMaxWidth is true (default)', () => {
    renderGraph(
      `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      { er: { useMaxWidth: true } }
    );
    cy.get('svg').should((svg) => {
      expect(svg).to.have.attr('width', '100%');
      // expect(svg).to.have.attr('height', '465');
      const style = svg.attr('style');
      expect(style).to.match(/^max-width: [\d.]+px;$/);
      const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
      // use within because the absolute value can be slightly different depending on the environment ±5%
      expect(maxWidthValue).to.be.within(140 * 0.95, 140 * 1.05);
    });
  });

  it('should render an ER when useMaxWidth is false', () => {
    renderGraph(
      `
    erDiagram
        CUSTOMER ||--o{ ORDER : places
        ORDER ||--|{ LINE-ITEM : contains
      `,
      { er: { useMaxWidth: false } }
    );
    cy.get('svg').should((svg) => {
      const width = parseFloat(svg.attr('width'));
      // use within because the absolute value can be slightly different depending on the environment ±5%
      expect(width).to.be.within(140 * 0.95, 140 * 1.05);
      // expect(svg).to.have.attr('height', '465');
      expect(svg).to.not.have.attr('style');
    });
  });

  it('should render entities that have no relationships', () => {
    renderGraph(
      `
    erDiagram
        DEAD_PARROT
        HERMIT
        RECLUSE
        SOCIALITE }o--o{ SOCIALITE : "interacts with"
        RECLUSE }o--o{ SOCIALITE : avoids
      `,
      { er: { useMaxWidth: false } }
    );
  });

  it('should render entities with and without attributes', () => {
    renderGraph(
      `
    erDiagram
        BOOK { string title }
        AUTHOR }|..|{ BOOK : writes
        BOOK { float price }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with generic and array attributes', () => {
    renderGraph(
      `
    erDiagram
        BOOK {
          string title
          string[] authors
          type~T~ type
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with length in attributes type', () => {
    renderGraph(
      `
    erDiagram
        CLUSTER {
          varchar(99) name
          string(255) description
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities and attributes with big and small entity names', () => {
    renderGraph(
      `
    erDiagram
        PRIVATE_FINANCIAL_INSTITUTION {
          string name
          int    turnover
        }
        PRIVATE_FINANCIAL_INSTITUTION ||..|{ EMPLOYEE : employs
        EMPLOYEE { bool officer_of_firm }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with attributes that begin with asterisk', () => {
    imgSnapshotTest(
      `
    erDiagram
        BOOK {
          int         *id
          string      name
          varchar(99) summary
        }
        BOOK }o..o{ STORE : soldBy
        STORE {
          int         *id
          string      name
          varchar(50) address
        }
        `,
      { loglevel: 1 }
    );
  });

  it('should render entities with keys', () => {
    renderGraph(
      `
    erDiagram
      AUTHOR_WITH_LONG_ENTITY_NAME {
        string name PK
      }
      AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
      BOOK {
          float price
          string author FK
          string title PK
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with comments', () => {
    renderGraph(
      `
    erDiagram
      AUTHOR_WITH_LONG_ENTITY_NAME {
        string name "comment"
      }
      AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
      BOOK {
          string author
          string title "author comment"
          float price "price comment"
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with keys and comments', () => {
    renderGraph(
      `
    erDiagram
      AUTHOR_WITH_LONG_ENTITY_NAME {
        string name PK "comment"
      }
      AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
      BOOK {
          string description
          float price "price comment"
          string title PK "title comment"
          string author FK
        }
      `,
      { logLevel: 1 }
    );
  });

  it('should render entities with aliases', () => {
    renderGraph(
      `
    erDiagram
      T1 one or zero to one or more T2 : test
      T2 one or many optionally to zero or one T3 : test
      T3 zero or more to zero or many T4 : test
      T4 many(0) to many(1) T5 : test
      T5 many optionally to one T6 : test
      T6 only one optionally to only one T1 : test
      T4 0+ to 1+ T6 : test
      T1 1 to 1 T3 : test
      `,
      { logLevel: 1 }
    );
  });

  it('1433: should render a simple ER diagram with a title', () => {
    imgSnapshotTest(
      `---
title: simple ER diagram
---
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
`,
      {}
    );
  });

  it('should render entities with entity name aliases', () => {
    imgSnapshotTest(
      `
    erDiagram
      p[Person] {
        varchar(64) firstName
        varchar(64) lastName
      }
      c["Customer Account"] {
        varchar(128) email
      }
      p ||--o| c : has
      `,
      { logLevel: 1 }
    );
  });
});
