import {
  Resource,
  Slot,
  component$,
  createComputed$,
  createSignal,
  isBrowser,
  untrack,
  useComputed$,
  useConstant,
  useResource$,
  useSignal,
  useStore,
  useStyles$,
  useTask$,
  useVisibleTask$,
  type QwikIntrinsicElements,
  type Signal,
} from '@qwik.dev/core';
import { delay } from '../resource/resource';
import {
  TestAC,
  TestACN,
  TestACNStr,
  TestACStr,
  TestC,
  TestCN,
  TestCNStr,
  TestCStr,
  TestCWithFlag,
} from './utils/utils';

export const Signals = component$(() => {
  const rerender = useSignal(0);
  return (
    <>
      <button id="rerender" onClick$={() => rerender.value++}>
        Rerender
      </button>
      <span id="rerender-count">Renders: {rerender.value}</span>
      <SignalsChildren key={untrack(() => rerender.value)} rerenderCount={rerender.value} />
    </>
  );
});
export const SignalsChildren = component$<{ rerenderCount: number }>(({ rerenderCount }) => {
  const ref = useSignal<Element>();
  const ref2 = useSignal<Element>();
  const id = useSignal(0);
  const signal = useSignal('');
  const renders = useStore(
    {
      count: 0,
    },
    { reactive: false }
  );
  const store = useStore({
    foo: 10,
    attribute: 'even',
    signal,
  });

  const styles = useSignal('body { background: white}');

  useVisibleTask$(() => {
    ref.value!.setAttribute('data-set', 'ref');
    ref2.value!.setAttribute('data-set', 'ref2');
  });

  renders.count++;
  const rerenders = renders.count + 0;
  return (
    <div aria-label={store.attribute}>
      <button
        id="count"
        onClick$={() => {
          store.foo++;
          store.attribute = store.foo % 2 === 0 ? 'even' : 'odd';
        }}
      >
        Increment
      </button>
      <button
        id="click"
        onClick$={() => {
          signal.value = 'clicked';
        }}
      >
        Click
      </button>
      <button
        id="increment-id"
        onClick$={() => {
          id.value++;
        }}
      >
        Increment ID
      </button>
      <button
        id="background"
        onClick$={() => {
          styles.value = 'body { background: black }';
        }}
      >
        Black background
      </button>
      <div id="parent-renders">Parent renders: {rerenders}</div>
      <Child
        text="Message"
        count={store.foo}
        ref={ref}
        ref2={ref2}
        signal={signal}
        signal2={store.signal}
        id={id.value}
        styles={styles.value}
      />
      <SignalTextNodeReplacementAndWhitespaceIssue1681 />
      <StoreConditionalRenderingIssue1733 />
      <SideEffect />
      <StateReactivityComparisonIssue1884 />
      <SignalVsStorePropsReactivityIssue2176 />
      <ClassReactivitySignalStoreIssue2245 />
      <ClassReactivitySignalStoreBIssue2245 />
      <ComplexClassSignals />
      <TernaryDomNodeUpdateIssue2311 />
      <TextareaValueSignalUpdateIssue2344 />
      <FormFieldStoreValuesIssue2928 />
      <UseStoreDeepDomUpdateIssue2930 />
      <SignalDestructuringInChildIssue3212 />
      <FineGrainedTextSub />
      <FineGrainedUnsubs />
      <DangerouslySetInnerHtmlSignalIssue3415 />
      <BindSignal />
      <StoreDataAttributeKeyIssue3482 />
      <StoreCustomKeysSerializationIssue3663 />
      <SignalSerializationNullErrorIssue3440 />
      <UseStoreUninitializedKeysIssue4174 />
      <SignalsTernaryUnnecessaryRerendersIssue4249 />
      <ExcessiveRerenderingStorePropsIssue4228 />
      <PropsSpreadingUseResourceReactivityIssue4368 />
      <UseComputedValueNotReflectedIssue4868 />
      <ManySignals />
      <span id="rerender-check">{rerenderCount}</span>
    </div>
  );
});

interface ChildProps {
  count: number;
  text: string;
  ref: Signal<Element | undefined>;
  ref2: Signal<Element | undefined>;
  signal: Signal<string>;
  signal2: Signal<string>;
  id: number;
  styles: string;
}
export const Child = component$((props: ChildProps) => {
  const renders = useStore(
    {
      count: 0,
    },
    { reactive: false }
  );
  renders.count++;
  const rerenders = renders.count + 0;
  return (
    <>
      <div id="child-renders">Child renders: {rerenders}</div>
      <div id="text" ref={props.ref}>
        Text: {props.text}
      </div>
      <Id id={props.id} />
      <div id="computed">{'computed: ' + props.signal.value}</div>
      <div id="stuff" ref={props.ref2}>
        Stuff: {props.count}
      </div>
      <style>{props.styles}</style>
      <textarea id="textarea" value={props.styles}></textarea>
    </>
  );
});

export const Id = (props: any) => <div id="id">Id: {props.id}</div>;

export const C = ({ who, count }: any) => (
  <>
    Count {who} is {count}
  </>
);

export const SignalTextNodeReplacementAndWhitespaceIssue1681 = component$(() => {
  const signal = useSignal(0);

  return (
    <div>
      <button id="issue-1681-btn" onClick$={() => signal.value++}>
        Click
      </button>{' '}
      <span id="issue-1681-return">
        <C who={'A'} count={signal.value} /> <C who={'B'} count={signal} />
      </span>
    </div>
  );
});

export const StoreConditionalRenderingIssue1733 = component$(() => {
  const store = useStore({ open: false });
  return (
    <>
      <button id="issue1733-btn" onClick$={() => (store.open = !store.open)}>
        toggle
      </button>
      <p id="issue1733-signal">{store.open}</p>
      <p id="issue1733-false">{false}</p>
      <p id="issue1733-true">{true}</p>
      {store.open && <h1 id="issue1733-h1">Message</h1>}
    </>
  );
});

export const SideEffect = component$(() => {
  const signal = useSignal('initial');
  useTask$(async () => {
    await delay(100);
    signal.value = 'set';
  });
  return (
    <>
      <div>{signal.value}</div>
    </>
  );
});

export const StateReactivityComparisonIssue1884 = component$(() => {
  const state = useStore({
    value: '',
    bool: false,
    counter: 0,
  });
  return (
    <>
      <button
        id="issue1884-btn"
        onClick$={() => {
          state.value = 'test';
          state.counter++;
          state.bool = true;
        }}
      >
        Click me {state.counter}
      </button>
      <div>
        <Test active={state.value === 'test'} />
        <Test active={state.bool ? true : false} />
        <Test active={state.bool} />
        <Test active={state.value} />
      </div>
    </>
  );
});

export const Test = component$(({ active }: { active: boolean | string }) => {
  return (
    <div class="issue1884-text" style={{ color: active && ('red' as any) }}>
      Should turn red
    </div>
  );
});

export const SignalVsStorePropsReactivityIssue2176 = component$(() => {
  const data = useSignal({ text: 'testing', flag: false, num: 1 });
  const store = useStore({ text: 'testing', flag: false, num: 1 });
  return (
    <div>
      <button
        id="issue-2176-btn"
        onClick$={() => {
          const nu = data.value.num + 1;
          const text = 'testing' + nu;
          data.value = { text, flag: !data.value.flag, num: nu };
          store.num = nu;
          store.text = text;
          store.flag = !store.flag;
        }}
      >
        Click me to change the data
      </button>
      {/* <code>{JSON.stringify(data.value)}</code> */}

      <h2>Signal</h2>
      <ul>
        <li>
          <Test1 text={data.value.text} flag={data.value.flag} num={data.value.num}>
            Nested value
          </Test1>
        </li>
        <li>
          <Test1Sig sig={data}>Raw </Test1Sig>
        </li>
        <li>
          <Test2
            text={`${data.value.text} flag=${data.value.flag ? 'T' : 'F'} num=${data.value.num}`}
          >
            Computed prop
          </Test2>
        </li>
        <li>
          <Test2Sig sig={data}>Raw + Computed</Test2Sig>
        </li>
        <li>
          <Test2Child>
            Slot{' '}
            <span class="issue-2176-result">
              {data.value.text} flag={data.value.flag ? 'T' : 'F'} num=
              {data.value.num}
            </span>
          </Test2Child>
        </li>
        <li>
          <Test2Child>
            Computed + Slot{' '}
            <span class="issue-2176-result">
              {`${data.value.text} flag=${data.value.flag ? 'T' : 'F'} num=${data.value.num}`}
            </span>
          </Test2Child>
        </li>
      </ul>

      <h2>Store</h2>
      <ul>
        <li>
          <Test1 text={store.text} flag={store.flag} num={store.num}>
            Nested value
          </Test1>
        </li>
        <li>
          <TestStore store={store}>Raw</TestStore>
        </li>
        <li>
          <Test2 text={`${store.text} flag=${store.flag ? 'T' : 'F'} num=${store.num}`}>
            Computed prop
          </Test2>
        </li>
        <li>
          <Test2Store store={store}>Raw + Computed</Test2Store>
        </li>
        <li>
          <Test2Child>
            Slot{' '}
            <span class="issue-2176-result">
              {store.text} flag={store.flag ? 'T' : 'F'} num={store.num}
            </span>
          </Test2Child>
        </li>
        <li>
          <Test2Child>
            Computed + Slot{' '}
            <span class="issue-2176-result">
              {`${store.text} flag=${store.flag ? 'T' : 'F'} num=${store.num}`}
            </span>
          </Test2Child>
        </li>
      </ul>
    </div>
  );
});

export const Test1 = component$((props: { text: string; flag: boolean; num: number }) => {
  return (
    <p>
      <Slot />{' '}
      <span class="issue-2176-result">
        {props.text} flag={props.flag ? 'T' : 'F'} num={props.num}
      </span>
    </p>
  );
});
export const Test1Sig = component$((props: { sig: Signal }) => {
  return (
    <p>
      <Slot />{' '}
      <span class="issue-2176-result">
        {props.sig.value.text} flag={props.sig.value.flag ? 'T' : 'F'} num=
        {props.sig.value.num}
      </span>
    </p>
  );
});
export const TestStore = component$((props: { store: any }) => {
  return (
    <p>
      <Slot />{' '}
      <span class="issue-2176-result">
        {props.store.text} flag={props.store.flag ? 'T' : 'F'} num=
        {props.store.num}
      </span>
    </p>
  );
});
export const Test2 = component$((props: { text: string }) => {
  return (
    <p>
      <Slot /> <span class="issue-2176-result">{props.text}</span>
    </p>
  );
});
export const Test2Sig = component$((props: { sig: Signal }) => {
  return (
    <p>
      <Slot />{' '}
      <span class="issue-2176-result">
        {`${props.sig.value.text} flag=${
          props.sig.value.flag ? 'T' : 'F'
        } num=${props.sig.value.num}`}
      </span>
    </p>
  );
});
export const Test2Store = component$((props: { store: any }) => {
  return (
    <p>
      <Slot />{' '}
      <span class="issue-2176-result">
        {`${props.store.text} flag=${props.store.flag ? 'T' : 'F'} num=${props.store.num}`}
      </span>
    </p>
  );
});
export const Test2Child = component$(() => {
  return (
    <p>
      <Slot />
    </p>
  );
});

export const ClassReactivitySignalStoreIssue2245 = component$(() => {
  useStyles$(`
span.true { font-weight: bold; }
span.false { font-style: italic; }
.row { display:flex; flex-direction: row; }
.column { display:flex; flex-direction: column; }
p { padding: 0.5em; border:1px solid; margin:0.2em }
.black { color: black; border-color: black; }
.red { color: red; border-color: red; }
.blue { color: blue; border-color: blue; }
.green { color: green; border-color: green; }
.purple { color: purple; border-color: purple; }
`);

  const colors = ['black', 'red', 'blue', 'green', 'purple'];
  const store = useStore({ color: 'black', n: 0, flag: false });
  const colorSignal = useSignal('black');
  return (
    <div>
      <button
        id="issue-2245-btn"
        onClick$={() => {
          store.n++;
          store.flag = !store.flag;
          if (store.n >= colors.length) {
            store.n = 0;
          }
          store.color = colors[store.n];
          colorSignal.value = colors[store.n];
        }}
      >
        Click me to change the color
      </button>

      <div class="row">
        <div class="column issue-2245-results">
          <h3>Store - class</h3>
          <TestC color={store.color}>Class = OK</TestC>
          <TestAC color={store.color}>[Class] = OK</TestAC>
          <TestCStr color={store.color}>{`{Class}`} = OK</TestCStr>
          <TestACStr color={store.color}>{`[{Class}]`} = OK</TestACStr>

          <h3>Store - className</h3>
          <TestCN color={store.color}>ClassName = OK</TestCN>
          <TestACN color={store.color}>[ClassName] = OK (though JSX complains</TestACN>
          <TestCNStr color={store.color}>{`{ClassName}`} = OK</TestCNStr>
          <TestACNStr color={store.color}>{`[{ClassName}]`} = OK</TestACNStr>
        </div>

        <div class="column issue-2245-results">
          <h3>Signal - class</h3>
          <TestC color={colorSignal.value}>Class = OK</TestC>
          <TestAC color={colorSignal.value}>[Class] = OK</TestAC>
          <TestCStr color={colorSignal.value}>{`{Class}`} = OK</TestCStr>
          <TestACStr color={colorSignal.value}>{`[{Class}]`} = OK</TestACStr>

          <h3>Signal - className</h3>
          <TestCN color={colorSignal.value}>ClassName = Fail</TestCN>
          <TestACN color={colorSignal.value}>[ClassName] = OK (JSX complains)</TestACN>
          <TestCNStr color={colorSignal.value}>{`{ClassName}`} = OK</TestCNStr>
          <TestACNStr color={colorSignal.value}>{`[{ClassName}]`} = OK (JSX complains)</TestACNStr>
        </div>
      </div>
    </div>
  );
});

export const ClassReactivitySignalStoreBIssue2245 = component$(() => {
  const colors = ['black', 'red', 'blue', 'green', 'purple'];
  const store = useStore({ color: 'black', n: 0, flag: false });
  const colorSignal = useSignal('black');
  const flagSignal = useSignal(false);
  return (
    <div>
      <button
        id="issue-2245-b-btn"
        onClick$={() => {
          store.n++;
          store.flag = !store.flag;
          flagSignal.value = !flagSignal.value;
          if (store.n >= colors.length) {
            store.n = 0;
          }
          store.color = colors[store.n];
          colorSignal.value = colors[store.n];
        }}
      >
        Click me to change the color
      </button>
      <div>
        FLAG: <code>{store.flag ? 'bold' : 'italic'} </code>
      </div>
      <div>
        <code>STORE: {JSON.stringify(store.color)}</code>
      </div>

      <div class="column issue-2245-b-results">
        <TestCWithFlag color={store.color} flag={store.flag}>
          Class = Fail
        </TestCWithFlag>
      </div>
    </div>
  );
});

export const ComplexClassSignals = component$(() => {
  const classes = useSignal(['initial', { hidden: false, visible: true }]);
  return (
    <div>
      <button
        id="complex-classes-btn"
        onClick$={() => {
          classes.value = ['change', { hidden: true, visible: false }];
        }}
      >
        Change classses
      </button>
      <div id="complex-classes-results" class={classes.value}>
        Div with classes
      </div>
    </div>
  );
});

type MyStore = {
  condition: boolean;
  text: string;
};

export const TernaryDomNodeUpdateIssue2311 = component$(() => {
  const store = useStore<MyStore>({
    condition: false,
    text: 'Hello',
  });

  useTask$(({ track }) => {
    const v = track(() => store.condition);
    if (v) {
      store.text = 'Bye bye 👻';
    }
  });

  return (
    <div>
      <h1>Weird DOM update bug?</h1>

      <div>
        <button
          id="issue-2311-btn"
          onClick$={() => {
            store.condition = true;
          }}
        >
          Make it so
        </button>
      </div>

      <div id="issue-2311-results">
        <p>This text should not change</p>
        <>{store.condition ? <b>Done!</b> : <p>{store.text}</p>}</>

        <p>This text should not change</p>
        <>{store.condition ? <b>Done!</b> : <p>{store.text}</p>}</>

        <p>This text should not change</p>
        <>{store.condition ? <b>Done!</b> : <p>{store.text}</p>}</>

        <p>This text should not change</p>
        <>{store.condition ? <b>Done!</b> : <p>{store.text}</p>}</>

        <p>This text should not change</p>
        <>{store.condition ? <b>Done!</b> : <p>{store.text}</p>}</>
      </div>
    </div>
  );
});

export const TextareaValueSignalUpdateIssue2344 = component$(() => {
  const classSig = useSignal('abc');
  return (
    <>
      <textarea id="issue-2344-results" value="Content" rows={5}></textarea>
      {classSig.value + ''}
      <p>
        <button
          id="issue-2344-btn"
          onClick$={() => {
            classSig.value = 'bar';
          }}
        >
          Should not error
        </button>
      </p>
    </>
  );
});

export const FormFieldStoreValuesIssue2928 = component$(() => {
  const store = useStore(
    {
      controls: {
        age: {
          value: 1,
          valid: true,
        },
      },
    },
    {
      deep: true,
    }
  );
  const group = {
    controls: store.controls,
  };

  return (
    <div>
      <button
        onClick$={async (e) => {
          group.controls.age.value++;
          await delayZero();
          group.controls.age.valid = false;
        }}
      >
        Increment
      </button>
      <FormDebug ctrl={group.controls.age} />
      {group.controls.age.value == 2 && <div>match!</div>}
    </div>
  );
});

export const FormDebug = component$<{ ctrl: any }>((props) => {
  return (
    <div>
      value:{' this_breaks!! '} -<>{props.ctrl.value} </>
      <>{props.ctrl.value + ''} </>
    </div>
  );
});

export const UseStoreDeepDomUpdateIssue2930 = component$(() => {
  const group = useStore(
    {
      controls: {
        ctrl: {
          value: '',
        },
      },
    },
    {
      deep: true,
    }
  );

  return (
    <div>
      <div>Type into input field:</div>
      <input
        id="issue-2930-input"
        style="border: 1px solid black"
        type="text"
        value={group.controls.ctrl.value}
        onInput$={(ev, el) => {
          group.controls.ctrl.value = el.value;
        }}
      />
      <Stringify data={group} />

      <Stringify data={group.controls} />

      <Stringify data={group.controls.ctrl} />

      <Stringify data={group.controls.ctrl.value} />
    </div>
  );
});

export const Stringify = component$<{
  data: any;
  style?: any;
}>((props) => {
  return <pre class="issue-2930-result">{JSON.stringify(props.data)}</pre>;
});

export const SignalDestructuringInChildIssue3212Child = component$(
  (props: { signal: Signal<number> }) => {
    return <>{props.signal.value}</>;
  }
);

export function useMySignal() {
  const signal = useSignal<number>(1);
  return { signal };
}

export const SignalDestructuringInChildIssue3212 = component$(() => {
  const stuff = useMySignal();
  const signal = stuff.signal;
  return (
    <div>
      <h2>SignalDestructuringInChildIssue3212</h2>
      <div id="issue-3212-result-0">
        <SignalDestructuringInChildIssue3212Child signal={stuff.signal} />
      </div>
      <div id="issue-3212-result-1">{stuff.signal.value}</div>
      <div id="issue-3212-result-2">{stuff.signal}</div>
      <div id="issue-3212-result-3">{signal}</div>
    </div>
  );
});

export const delayZero = () => {
  return new Promise((resolve) => {
    setTimeout(resolve, 1);
  });
};

export const FineGrainedTextSub = component$(() => {
  const count = useSignal(0);
  const computed = count.value + 2;

  return (
    <div>
      <h2>Fine Grained</h2>
      <div id="fine-grained-mutable" data-value={computed}>
        {computed}
      </div>
      <div>
        <button id="fine-grained-signal" data-value={count.value} onClick$={() => count.value++}>
          Increment {count.value}
        </button>
      </div>
    </div>
  );
});

export const FineGrainedUnsubs = component$(() => {
  const count = useSignal<{ nu: number } | undefined>({ nu: 1 });
  console.warn(count.value);

  return (
    <div>
      <h2>Fine Grained Unsubs</h2>
      <button
        id="fine-grained-unsubs-toggle"
        onClick$={() => {
          if (count.value) {
            count.value = undefined;
          } else {
            count.value = { nu: 123 };
          }
        }}
      >
        Toggle
      </button>

      {count.value && (
        <div id="fine-grained-unsubs" data-value={count.value.nu}>
          {count.value.nu}
        </div>
      )}
      <div>{count.value?.nu ?? 'EMPTY'}</div>
    </div>
  );
});

export const DangerouslySetInnerHtmlSignalIssue3415 = component$(() => {
  const signal = useSignal('<b>foo</b>');

  return (
    <>
      <button
        id="issue-3415-button"
        onClick$={() => {
          signal.value = '<i>bar</i>';
        }}
      >
        Toggle
      </button>
      <div id="issue-3415-result" dangerouslySetInnerHTML={signal.value} />
    </>
  );
});

export const BindSignal = component$(() => {
  const value = useSignal('initial');
  const checked = useSignal(false);

  return (
    <>
      <input id="bind-checkbox" type="checkbox" bind:checked={checked} />
      <input id="bind-input-1" bind:value={value} disabled={checked.value} />
      <div id="bind-text-1">Value: {value}</div>
      <div id="bind-text-2">Value: {value.value}</div>
      <textarea id="bind-input-2" bind:value={value} disabled={checked.value} />
      <input id="bind-checkbox-2" type="checkbox" bind:checked={checked} />
    </>
  );
});

export const StoreDataAttributeKeyIssue3482 = component$(() => {
  const count = useStore({
    'data-foo': 0,
  });

  return (
    <>
      <button
        id="issue-3482-button"
        data-count={count['data-foo']}
        onClick$={() => count['data-foo']++}
      >
        Increment {count['data-foo']}
      </button>
      <div id="issue-3482-result" data-count={count['data-foo']}>
        {count['data-foo']}
      </div>
    </>
  );
});

export const StoreCustomKeysSerializationIssue3663 = component$(() => {
  const store = useStore({
    'Custom Counter': 0,
  });
  const a = store['Custom Counter'] + 0;
  return (
    <div>
      <button id="issue-3663-button" onClick$={() => store['Custom Counter']++}>
        Increment
      </button>
      <div class="issue-3663-result" data-value={store['Custom Counter']}>
        {store['Custom Counter']}
      </div>
      <StoreCustomKeysSerializationIssue3663Cmp prop={store['Custom Counter']} />
      <div class="issue-3663-result" data-value={a}>
        {a}
      </div>
    </div>
  );
});

function StoreCustomKeysSerializationIssue3663Cmp(props: { prop: number }) {
  return (
    <div class="issue-3663-result" data-value={props.prop}>
      {props.prop}
    </div>
  );
}

export const SignalSerializationNullErrorIssue3440 = component$(() => {
  const name = useSignal('Demo');
  const blogs = useStore([
    {
      id: 1,
      title: 'my first blog',
    },
    {
      id: 2,
      title: 'my second blogs',
    },
    {
      id: 3,
      title: 'my third blog',
    },
  ]);
  return (
    <>
      <div>
        <div>
          <h1>Name: {name.value}</h1>
          {blogs.map((blog) => (
            <div class="issue-3440-results" key={blog.id}>
              {blog.title}
            </div>
          ))}
          <button id="issue-3440-remove" onClick$={() => blogs.pop()}>
            Remove Blog
          </button>
        </div>
      </div>
    </>
  );
});

export const UseStoreUninitializedKeysIssue4174 = component$(() => {
  const storeWithoutInit = useStore<{ value?: string }>({});

  useVisibleTask$(
    () => {
      storeWithoutInit.value = 'visible-task';
    },
    { strategy: 'document-ready' }
  );

  return (
    <>
      <div id="issue-4174-result">Store: {storeWithoutInit.value}</div>
    </>
  );
});

export const SignalsTernaryUnnecessaryRerendersIssue4249 = component$(() => {
  const first = useSignal('');
  const second = useSignal('');

  return (
    <main>
      <div>
        <label for="first">
          {'First '}
          <input
            id="issue-4249-first"
            value={first.value}
            onInput$={(_, e) => (first.value = e.value)}
            placeholder="type here"
          />
        </label>
      </div>
      <div>
        <label for="second">
          {'Second '}
          <input
            id="issue-4249-second"
            value={second.value}
            onInput$={(_, e) => (second.value = e.value)}
            placeholder="type here"
          />
        </label>
      </div>

      <div
        id="issue-4249-result"
        data-value={
          first.value && second.value && first.value === second.value ? 'collision' : 'no-collision'
        }
      >
        {'Status: '}
        {first.value && second.value && first.value === second.value
          ? 'Collision detected'
          : 'No collision'}
      </div>
    </main>
  );
});

type Counters = {
  countA: number;
  countB: number;
  signal: Signal<number>;
};

type Props = {
  counters: Counters;
};

export const DisplayA = component$<Props>(({ counters }) => {
  return (
    <>
      Display A:{' '}
      <span id="issue-4228-result-a">{`${counters.countA}:${
        typeof (globalThis as any).countA === 'number' ? (window as any).countA++ : 0
      }`}</span>
    </>
  );
});
export const DisplayB = component$<Props>(({ counters }) => {
  return (
    <>
      Display B:{' '}
      <span id="issue-4228-result-b">{`${counters.countB}:${
        typeof (globalThis as any).countB === 'number' ? (window as any).countB++ : 0
      }`}</span>
    </>
  );
});
export const DisplaySignal = component$<Props>(({ counters }) => {
  return (
    <>
      Display C:{' '}
      <span id="issue-4228-result-c">{`${counters.signal.value}:${
        typeof (globalThis as any).countC === 'number' ? (window as any).countC++ : 0
      }`}</span>
    </>
  );
});
export const DisplayTotal = component$<Props>(({ counters }) => {
  return (
    <>
      Display Total:{' '}
      <span id="issue-4228-result-total">{`${
        counters.countA + counters.countB + counters.signal.value
      }:${typeof (globalThis as any).countD === 'number' ? (window as any).countD++ : 0}`}</span>
    </>
  );
});
export const ExcessiveRerenderingStorePropsIssue4228 = component$(() => {
  const signal = useSignal(0);
  const counter = useStore({
    countA: 0,
    countB: 0,
    signal,
  });
  useTask$(() => {
    if (isBrowser) {
      (window as any).countA = 0;
      (window as any).countB = 0;
      (window as any).countC = 0;
      (window as any).countD = 0;
    }
  });
  useVisibleTask$(
    () => {
      (window as any).countA = 1;
      (window as any).countB = 1;
      (window as any).countC = 1;
      (window as any).countD = 1;
    },
    {
      strategy: 'document-ready',
    }
  );
  return (
    <>
      <p>
        <button id="issue-4228-button-a" onClick$={() => counter.countA++}>
          +1 A
        </button>
        <DisplayA counters={counter} />
      </p>
      <p>
        <button id="issue-4228-button-b" onClick$={() => counter.countB++}>
          +1 B
        </button>
        <DisplayB counters={counter} />
      </p>
      <p>
        <button id="issue-4228-button-c" onClick$={() => signal.value++}>
          +1 Signal
        </button>
        <DisplaySignal counters={counter} />
      </p>
      <p>
        <DisplayTotal counters={counter} />
      </p>
    </>
  );
});

const MyButton = component$<QwikIntrinsicElements['button']>(({ type, ...rest }) => {
  return (
    <button id="issue-4368-button" type={type || 'button'} {...rest}>
      <Slot />
    </button>
  );
});

const MyTextButton = component$<{ text: string }>((props) => {
  return (
    <MyButton disabled={!props.text}>{props.text ? 'Example button' : 'Text is empty'}</MyButton>
  );
});

export const PropsSpreadingUseResourceReactivityIssue4368 = component$(() => {
  const text = useSignal('');

  const textResource = useResource$(async (ctx) => {
    return ctx.track(() => text.value);
  });

  return (
    <>
      <input id="issue-4368-input" bind:value={text} placeholder="type something here" />

      <Resource
        value={textResource}
        onRejected={() => <p>Error</p>}
        onPending={() => <p>Loading</p>}
        onResolved={(resolved) => (
          <>
            <MyTextButton text={resolved} />
          </>
        )}
      />
    </>
  );
});

export const __CFG__ = { noImg: 'https://placehold.co/600x400?text=No%20IMG' };

export type PropsType = {
  data: { id: number; src?: string };
};

const options = [
  {
    src: 'https://placehold.co/400x400?text=1',
    id: 1,
  },
  {
    src: 'https://placehold.co/500x500?text=2',
    id: 2,
  },
];

export const UseComputedValueNotReflectedIssue4868 = component$(() => {
  const selected = useSignal<{ id: number; src?: string }>(options[0]);
  return (
    <div>
      <UseComputedValueNotReflectedIssue4868BigCard data={selected.value} />
      {options.map((d) => (
        <>
          <button
            key={d.id}
            onClick$={() => (selected.value = d)}
            style={{ padding: '2rem', cursor: 'pointer' }}
            id={`issue-4868-btn-${d.id}`}
          >
            {d.id}
          </button>
        </>
      ))}
    </div>
  );
});

export const UseComputedValueNotReflectedIssue4868BigCard = component$<PropsType>((props) => {
  // Using a reference to another const will somehow prevent the useComputed$ in the Card element to use the correct context
  const noImg = __CFG__.noImg;

  // Assigning static value here will make the Card component and useComputed$ within work as expected
  // const noImg = 'https://placehold.co/600x400?text=No%20IMG';

  return (
    <div
      style={{
        flexDirection: 'column',
        border: '1px solid red',
        padding: '1rem',
        gap: '1rem',
      }}
    >
      <UseComputedValueNotReflectedIssue4868Card src={props.data.src || noImg} />
      <div id="issue-4868-json">{JSON.stringify(props.data)}</div>
    </div>
  );
});

export const UseComputedValueNotReflectedIssue4868Card = component$((props: { src: string }) => {
  const { src } = props;

  const src$ = useComputed$(() => {
    // do something very important with the src
    return props.src + '&useComputed$';
  });

  return (
    <div style={{ border: '1px solid white', padding: '1rem' }}>
      <p id="issue-4868-props">Card props.src: {src}</p>
      <p id="issue-4868-usecomputed">Card useComputed$: {src$.value}</p>
    </div>
  );
});

export const ManySignals = component$(() => {
  const signals = useConstant(() => {
    const arr: (Signal<number> | string)[] = [];
    for (let i = 0; i < 10; i++) {
      arr.push(createSignal(0));
      arr.push(', ');
    }
    return arr;
  });
  const doubles = useConstant(() =>
    signals.map((s: Signal<number> | string) =>
      typeof s === 'string' ? s : createComputed$(() => s.value * 2)
    )
  );

  return (
    <>
      <button
        id="many-signals-button"
        onClick$={() => {
          for (const s of signals) {
            if (typeof s !== 'string') {
              s.value++;
            }
          }
        }}
      >
        Increment
      </button>
      <div id="many-signals-result">{signals}</div>
      <div id="many-doubles-result">{doubles}</div>
    </>
  );
});
